xref: /petsc/src/dm/impls/plex/plexpartition.c (revision 0134a67b057322d4851f6269ae24f60bfc3170ec)
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 
30*0134a67bSLisandro Dalcin PETSC_STATIC_INLINE PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }
31*0134a67bSLisandro 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);
87*0134a67bSLisandro 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);
95*0134a67bSLisandro 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    */
104*0134a67bSLisandro 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);
109*0134a67bSLisandro 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);
117*0134a67bSLisandro 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);
120*0134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1]]);
1218f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
122*0134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
123*0134a67bSLisandro Dalcin       }
124*0134a67bSLisandro Dalcin       /* Handle non-conforming meshes */
125*0134a67bSLisandro Dalcin       if (supportSize > 2) {
126*0134a67bSLisandro Dalcin         PetscInt        numChildren, i;
127*0134a67bSLisandro Dalcin         const PetscInt *children;
128*0134a67bSLisandro Dalcin 
129*0134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, f, &numChildren, &children);CHKERRQ(ierr);
130*0134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
131*0134a67bSLisandro Dalcin           const PetscInt child = children[i];
132*0134a67bSLisandro Dalcin           if (fStart <= child && child < fEnd) {
133*0134a67bSLisandro Dalcin             ierr = DMPlexGetSupport(dm, child, &support);CHKERRQ(ierr);
134*0134a67bSLisandro Dalcin             ierr = DMPlexGetSupportSize(dm, child, &supportSize);CHKERRQ(ierr);
135*0134a67bSLisandro Dalcin             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
136*0134a67bSLisandro Dalcin             else if (supportSize == 2) {
137*0134a67bSLisandro Dalcin               ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
138*0134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1]]);
139*0134a67bSLisandro Dalcin               ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
140*0134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
141*0134a67bSLisandro Dalcin             }
142*0134a67bSLisandro Dalcin           }
143*0134a67bSLisandro 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) {
158*0134a67bSLisandro Dalcin       const PetscInt gp = DMPlex_GlobalID(cellNum[p]);
159*0134a67bSLisandro Dalcin       PetscInt       coneSize, numChildren, c, i;
160*0134a67bSLisandro Dalcin       const PetscInt *cone, *children;
161*0134a67bSLisandro 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) {
165*0134a67bSLisandro Dalcin         const PetscInt point = cone[c];
166*0134a67bSLisandro 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);
170*0134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
171*0134a67bSLisandro Dalcin         }
172*0134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
173*0134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
174*0134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
175*0134a67bSLisandro Dalcin           const PetscInt child = children[i];
176*0134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
177*0134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
178*0134a67bSLisandro Dalcin             ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
179*0134a67bSLisandro Dalcin             ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
180*0134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
181*0134a67bSLisandro 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);
194*0134a67bSLisandro Dalcin         *pBuf = DMPlex_GlobalID(cellNum[point]);
195532c4e7dSMichael Lange       }
196532c4e7dSMichael Lange     }
1978cfe4c1fSMichael Lange     (*numVertices)++;
198532c4e7dSMichael Lange   }
1998f4e72b9SMatthew G. Knepley   ierr = PetscFree2(adjCells, remoteCells);CHKERRQ(ierr);
200b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, useCone, useClosure);CHKERRQ(ierr);
201532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
202532c4e7dSMichael Lange   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
203532c4e7dSMichael Lange   ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
204389e55d8SMichael Lange   ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
20543f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
20643f7d02bSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
20743f7d02bSMichael Lange     ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
20843f7d02bSMichael Lange   }
209532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
210532c4e7dSMichael Lange   if (offsets) *offsets = vOffsets;
211389e55d8SMichael Lange   ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
2128cfe4c1fSMichael Lange   ierr = ISRestoreIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
213f0927f4eSMatthew G. Knepley   ierr = ISDestroy(&cellNumbering);CHKERRQ(ierr);
214389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
215532c4e7dSMichael Lange   /* Clean up */
216532c4e7dSMichael Lange   ierr = PetscSegBufferDestroy(&adjBuffer);CHKERRQ(ierr);
217532c4e7dSMichael Lange   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
218532c4e7dSMichael Lange   ierr = PetscFree(adj);CHKERRQ(ierr);
219532c4e7dSMichael Lange   PetscFunctionReturn(0);
220532c4e7dSMichael Lange }
221532c4e7dSMichael Lange 
222d5577e40SMatthew G. Knepley /*@C
223d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
224d5577e40SMatthew G. Knepley 
225d5577e40SMatthew G. Knepley   Collective
226d5577e40SMatthew G. Knepley 
227d5577e40SMatthew G. Knepley   Input Arguments:
228d5577e40SMatthew G. Knepley + dm - The DMPlex
229d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
230d5577e40SMatthew G. Knepley 
231d5577e40SMatthew G. Knepley   Output Arguments:
232d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
233d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
234d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
235d5577e40SMatthew G. Knepley 
236d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
237d5577e40SMatthew G. Knepley 
238d5577e40SMatthew G. Knepley   Level: advanced
239d5577e40SMatthew G. Knepley 
240d5577e40SMatthew G. Knepley .seealso: DMPlexCreate()
241d5577e40SMatthew G. Knepley @*/
24270034214SMatthew G. Knepley PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
24370034214SMatthew G. Knepley {
24470034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
24570034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
24670034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
24770034214SMatthew G. Knepley   PetscInt      *off, *adj;
24870034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
24970034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
25070034214SMatthew G. Knepley   PetscErrorCode ierr;
25170034214SMatthew G. Knepley 
25270034214SMatthew G. Knepley   PetscFunctionBegin;
25370034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
254c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
25570034214SMatthew G. Knepley   cellDim = dim - cellHeight;
25670034214SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
25770034214SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
25870034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
25970034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
26070034214SMatthew G. Knepley     if (offsets)   *offsets   = NULL;
26170034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
26270034214SMatthew G. Knepley     PetscFunctionReturn(0);
26370034214SMatthew G. Knepley   }
26470034214SMatthew G. Knepley   numCells  = cEnd - cStart;
26570034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
26670034214SMatthew G. Knepley   if (dim == depth) {
26770034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
26870034214SMatthew G. Knepley 
26970034214SMatthew G. Knepley     ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
27070034214SMatthew G. Knepley     /* Count neighboring cells */
27170034214SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr);
27270034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
27370034214SMatthew G. Knepley       const PetscInt *support;
27470034214SMatthew G. Knepley       PetscInt        supportSize;
27570034214SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
27670034214SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
27770034214SMatthew G. Knepley       if (supportSize == 2) {
2789ffc88e4SToby Isaac         PetscInt numChildren;
2799ffc88e4SToby Isaac 
2809ffc88e4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
2819ffc88e4SToby Isaac         if (!numChildren) {
28270034214SMatthew G. Knepley           ++off[support[0]-cStart+1];
28370034214SMatthew G. Knepley           ++off[support[1]-cStart+1];
28470034214SMatthew G. Knepley         }
28570034214SMatthew G. Knepley       }
2869ffc88e4SToby Isaac     }
28770034214SMatthew G. Knepley     /* Prefix sum */
28870034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
28970034214SMatthew G. Knepley     if (adjacency) {
29070034214SMatthew G. Knepley       PetscInt *tmp;
29170034214SMatthew G. Knepley 
29270034214SMatthew G. Knepley       ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
293854ce69bSBarry Smith       ierr = PetscMalloc1(numCells+1, &tmp);CHKERRQ(ierr);
29470034214SMatthew G. Knepley       ierr = PetscMemcpy(tmp, off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
29570034214SMatthew G. Knepley       /* Get neighboring cells */
29670034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
29770034214SMatthew G. Knepley         const PetscInt *support;
29870034214SMatthew G. Knepley         PetscInt        supportSize;
29970034214SMatthew G. Knepley         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
30070034214SMatthew G. Knepley         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
30170034214SMatthew G. Knepley         if (supportSize == 2) {
3029ffc88e4SToby Isaac           PetscInt numChildren;
3039ffc88e4SToby Isaac 
3049ffc88e4SToby Isaac           ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
3059ffc88e4SToby Isaac           if (!numChildren) {
30670034214SMatthew G. Knepley             adj[tmp[support[0]-cStart]++] = support[1];
30770034214SMatthew G. Knepley             adj[tmp[support[1]-cStart]++] = support[0];
30870034214SMatthew G. Knepley           }
30970034214SMatthew G. Knepley         }
3109ffc88e4SToby Isaac       }
31170034214SMatthew G. Knepley #if defined(PETSC_USE_DEBUG)
31270034214SMatthew 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);
31370034214SMatthew G. Knepley #endif
31470034214SMatthew G. Knepley       ierr = PetscFree(tmp);CHKERRQ(ierr);
31570034214SMatthew G. Knepley     }
31670034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
31770034214SMatthew G. Knepley     if (offsets)   *offsets   = off;
31870034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
31970034214SMatthew G. Knepley     PetscFunctionReturn(0);
32070034214SMatthew G. Knepley   }
32170034214SMatthew G. Knepley   /* Setup face recognition */
32270034214SMatthew G. Knepley   if (faceDepth == 1) {
32370034214SMatthew 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 */
32470034214SMatthew G. Knepley 
32570034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
32670034214SMatthew G. Knepley       PetscInt corners;
32770034214SMatthew G. Knepley 
32870034214SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
32970034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
33070034214SMatthew G. Knepley         PetscInt nFV;
33170034214SMatthew G. Knepley 
33270034214SMatthew G. Knepley         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
33370034214SMatthew G. Knepley         cornersSeen[corners] = 1;
33470034214SMatthew G. Knepley 
33570034214SMatthew G. Knepley         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
33670034214SMatthew G. Knepley 
33770034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
33870034214SMatthew G. Knepley       }
33970034214SMatthew G. Knepley     }
34070034214SMatthew G. Knepley   }
34170034214SMatthew G. Knepley   ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
34270034214SMatthew G. Knepley   /* Count neighboring cells */
34370034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
34470034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
34570034214SMatthew G. Knepley 
3468b0b4c70SToby Isaac     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
34770034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
34870034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
34970034214SMatthew G. Knepley       PetscInt        cellPair[2];
35070034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
35170034214SMatthew G. Knepley       PetscInt        meetSize = 0;
35270034214SMatthew G. Knepley       const PetscInt *meet    = NULL;
35370034214SMatthew G. Knepley 
35470034214SMatthew G. Knepley       cellPair[0] = cell; cellPair[1] = neighborCells[n];
35570034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
35670034214SMatthew G. Knepley       if (!found) {
35770034214SMatthew G. Knepley         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
35870034214SMatthew G. Knepley         if (meetSize) {
35970034214SMatthew G. Knepley           PetscInt f;
36070034214SMatthew G. Knepley 
36170034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
36270034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
36370034214SMatthew G. Knepley               found = PETSC_TRUE;
36470034214SMatthew G. Knepley               break;
36570034214SMatthew G. Knepley             }
36670034214SMatthew G. Knepley           }
36770034214SMatthew G. Knepley         }
36870034214SMatthew G. Knepley         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
36970034214SMatthew G. Knepley       }
37070034214SMatthew G. Knepley       if (found) ++off[cell-cStart+1];
37170034214SMatthew G. Knepley     }
37270034214SMatthew G. Knepley   }
37370034214SMatthew G. Knepley   /* Prefix sum */
37470034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
37570034214SMatthew G. Knepley 
37670034214SMatthew G. Knepley   if (adjacency) {
37770034214SMatthew G. Knepley     ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
37870034214SMatthew G. Knepley     /* Get neighboring cells */
37970034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
38070034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
38170034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
38270034214SMatthew G. Knepley 
3838b0b4c70SToby Isaac       ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
38470034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
38570034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
38670034214SMatthew G. Knepley         PetscInt        cellPair[2];
38770034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
38870034214SMatthew G. Knepley         PetscInt        meetSize = 0;
38970034214SMatthew G. Knepley         const PetscInt *meet    = NULL;
39070034214SMatthew G. Knepley 
39170034214SMatthew G. Knepley         cellPair[0] = cell; cellPair[1] = neighborCells[n];
39270034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
39370034214SMatthew G. Knepley         if (!found) {
39470034214SMatthew G. Knepley           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
39570034214SMatthew G. Knepley           if (meetSize) {
39670034214SMatthew G. Knepley             PetscInt f;
39770034214SMatthew G. Knepley 
39870034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
39970034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
40070034214SMatthew G. Knepley                 found = PETSC_TRUE;
40170034214SMatthew G. Knepley                 break;
40270034214SMatthew G. Knepley               }
40370034214SMatthew G. Knepley             }
40470034214SMatthew G. Knepley           }
40570034214SMatthew G. Knepley           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
40670034214SMatthew G. Knepley         }
40770034214SMatthew G. Knepley         if (found) {
40870034214SMatthew G. Knepley           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
40970034214SMatthew G. Knepley           ++cellOffset;
41070034214SMatthew G. Knepley         }
41170034214SMatthew G. Knepley       }
41270034214SMatthew G. Knepley     }
41370034214SMatthew G. Knepley   }
41470034214SMatthew G. Knepley   ierr = PetscFree(neighborCells);CHKERRQ(ierr);
41570034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
41670034214SMatthew G. Knepley   if (offsets)   *offsets   = off;
41770034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
41870034214SMatthew G. Knepley   PetscFunctionReturn(0);
41970034214SMatthew G. Knepley }
42070034214SMatthew G. Knepley 
42177623264SMatthew G. Knepley /*@C
42277623264SMatthew G. Knepley   PetscPartitionerRegister - Adds a new PetscPartitioner implementation
42377623264SMatthew G. Knepley 
42477623264SMatthew G. Knepley   Not Collective
42577623264SMatthew G. Knepley 
42677623264SMatthew G. Knepley   Input Parameters:
42777623264SMatthew G. Knepley + name        - The name of a new user-defined creation routine
42877623264SMatthew G. Knepley - create_func - The creation routine itself
42977623264SMatthew G. Knepley 
43077623264SMatthew G. Knepley   Notes:
43177623264SMatthew G. Knepley   PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners
43277623264SMatthew G. Knepley 
43377623264SMatthew G. Knepley   Sample usage:
43477623264SMatthew G. Knepley .vb
43577623264SMatthew G. Knepley     PetscPartitionerRegister("my_part", MyPetscPartitionerCreate);
43677623264SMatthew G. Knepley .ve
43777623264SMatthew G. Knepley 
43877623264SMatthew G. Knepley   Then, your PetscPartitioner type can be chosen with the procedural interface via
43977623264SMatthew G. Knepley .vb
44077623264SMatthew G. Knepley     PetscPartitionerCreate(MPI_Comm, PetscPartitioner *);
44177623264SMatthew G. Knepley     PetscPartitionerSetType(PetscPartitioner, "my_part");
44277623264SMatthew G. Knepley .ve
44377623264SMatthew G. Knepley    or at runtime via the option
44477623264SMatthew G. Knepley .vb
44577623264SMatthew G. Knepley     -petscpartitioner_type my_part
44677623264SMatthew G. Knepley .ve
44777623264SMatthew G. Knepley 
44877623264SMatthew G. Knepley   Level: advanced
44977623264SMatthew G. Knepley 
45077623264SMatthew G. Knepley .keywords: PetscPartitioner, register
45177623264SMatthew G. Knepley .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy()
45277623264SMatthew G. Knepley 
45377623264SMatthew G. Knepley @*/
45477623264SMatthew G. Knepley PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner))
45577623264SMatthew G. Knepley {
45677623264SMatthew G. Knepley   PetscErrorCode ierr;
45777623264SMatthew G. Knepley 
45877623264SMatthew G. Knepley   PetscFunctionBegin;
45977623264SMatthew G. Knepley   ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr);
46077623264SMatthew G. Knepley   PetscFunctionReturn(0);
46177623264SMatthew G. Knepley }
46277623264SMatthew G. Knepley 
46377623264SMatthew G. Knepley /*@C
46477623264SMatthew G. Knepley   PetscPartitionerSetType - Builds a particular PetscPartitioner
46577623264SMatthew G. Knepley 
46677623264SMatthew G. Knepley   Collective on PetscPartitioner
46777623264SMatthew G. Knepley 
46877623264SMatthew G. Knepley   Input Parameters:
46977623264SMatthew G. Knepley + part - The PetscPartitioner object
47077623264SMatthew G. Knepley - name - The kind of partitioner
47177623264SMatthew G. Knepley 
47277623264SMatthew G. Knepley   Options Database Key:
47377623264SMatthew G. Knepley . -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types
47477623264SMatthew G. Knepley 
47577623264SMatthew G. Knepley   Level: intermediate
47677623264SMatthew G. Knepley 
47777623264SMatthew G. Knepley .keywords: PetscPartitioner, set, type
47877623264SMatthew G. Knepley .seealso: PetscPartitionerGetType(), PetscPartitionerCreate()
47977623264SMatthew G. Knepley @*/
48077623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name)
48177623264SMatthew G. Knepley {
48277623264SMatthew G. Knepley   PetscErrorCode (*r)(PetscPartitioner);
48377623264SMatthew G. Knepley   PetscBool      match;
48477623264SMatthew G. Knepley   PetscErrorCode ierr;
48577623264SMatthew G. Knepley 
48677623264SMatthew G. Knepley   PetscFunctionBegin;
48777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
48877623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr);
48977623264SMatthew G. Knepley   if (match) PetscFunctionReturn(0);
49077623264SMatthew G. Knepley 
4910f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
49277623264SMatthew G. Knepley   ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr);
49377623264SMatthew G. Knepley   if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name);
49477623264SMatthew G. Knepley 
49577623264SMatthew G. Knepley   if (part->ops->destroy) {
49677623264SMatthew G. Knepley     ierr              = (*part->ops->destroy)(part);CHKERRQ(ierr);
49777623264SMatthew G. Knepley   }
49809161815SVaclav Hapla   ierr = PetscMemzero(part->ops, sizeof(struct _PetscPartitionerOps));CHKERRQ(ierr);
49977623264SMatthew G. Knepley   ierr = (*r)(part);CHKERRQ(ierr);
50077623264SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr);
50177623264SMatthew G. Knepley   PetscFunctionReturn(0);
50277623264SMatthew G. Knepley }
50377623264SMatthew G. Knepley 
50477623264SMatthew G. Knepley /*@C
50577623264SMatthew G. Knepley   PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object.
50677623264SMatthew G. Knepley 
50777623264SMatthew G. Knepley   Not Collective
50877623264SMatthew G. Knepley 
50977623264SMatthew G. Knepley   Input Parameter:
51077623264SMatthew G. Knepley . part - The PetscPartitioner
51177623264SMatthew G. Knepley 
51277623264SMatthew G. Knepley   Output Parameter:
51377623264SMatthew G. Knepley . name - The PetscPartitioner type name
51477623264SMatthew G. Knepley 
51577623264SMatthew G. Knepley   Level: intermediate
51677623264SMatthew G. Knepley 
51777623264SMatthew G. Knepley .keywords: PetscPartitioner, get, type, name
51877623264SMatthew G. Knepley .seealso: PetscPartitionerSetType(), PetscPartitionerCreate()
51977623264SMatthew G. Knepley @*/
52077623264SMatthew G. Knepley PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name)
52177623264SMatthew G. Knepley {
52277623264SMatthew G. Knepley   PetscErrorCode ierr;
52377623264SMatthew G. Knepley 
52477623264SMatthew G. Knepley   PetscFunctionBegin;
52577623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
52677623264SMatthew G. Knepley   PetscValidPointer(name, 2);
5270f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
52877623264SMatthew G. Knepley   *name = ((PetscObject) part)->type_name;
52977623264SMatthew G. Knepley   PetscFunctionReturn(0);
53077623264SMatthew G. Knepley }
53177623264SMatthew G. Knepley 
53277623264SMatthew G. Knepley /*@C
53377623264SMatthew G. Knepley   PetscPartitionerView - Views a PetscPartitioner
53477623264SMatthew G. Knepley 
53577623264SMatthew G. Knepley   Collective on PetscPartitioner
53677623264SMatthew G. Knepley 
53777623264SMatthew G. Knepley   Input Parameter:
53877623264SMatthew G. Knepley + part - the PetscPartitioner object to view
53977623264SMatthew G. Knepley - v    - the viewer
54077623264SMatthew G. Knepley 
54177623264SMatthew G. Knepley   Level: developer
54277623264SMatthew G. Knepley 
54377623264SMatthew G. Knepley .seealso: PetscPartitionerDestroy()
54477623264SMatthew G. Knepley @*/
54577623264SMatthew G. Knepley PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v)
54677623264SMatthew G. Knepley {
547ffc59708SMatthew G. Knepley   PetscMPIInt    size;
5482abdaa70SMatthew G. Knepley   PetscBool      isascii;
54977623264SMatthew G. Knepley   PetscErrorCode ierr;
55077623264SMatthew G. Knepley 
55177623264SMatthew G. Knepley   PetscFunctionBegin;
55277623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
55377623264SMatthew G. Knepley   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);}
5542abdaa70SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
5552abdaa70SMatthew G. Knepley   if (isascii) {
5562abdaa70SMatthew G. Knepley     ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
557ffc59708SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "Graph Partitioner: %d MPI Process%s\n", size, size > 1 ? "es" : "");CHKERRQ(ierr);
5582abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "  type: %s\n", part->hdr.type_name);CHKERRQ(ierr);
5592abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr);
5602abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "edge cut: %D\n", part->edgeCut);CHKERRQ(ierr);
5612abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "balance:  %.2g\n", part->balance);CHKERRQ(ierr);
5622abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr);
5632abdaa70SMatthew G. Knepley   }
56477623264SMatthew G. Knepley   if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);}
56577623264SMatthew G. Knepley   PetscFunctionReturn(0);
56677623264SMatthew G. Knepley }
56777623264SMatthew G. Knepley 
568a0058e54SToby Isaac static PetscErrorCode PetscPartitionerGetDefaultType(const char *currentType, const char **defaultType)
569a0058e54SToby Isaac {
570a0058e54SToby Isaac   PetscFunctionBegin;
571a0058e54SToby Isaac   if (!currentType) {
572a0058e54SToby Isaac #if defined(PETSC_HAVE_CHACO)
573a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERCHACO;
574a0058e54SToby Isaac #elif defined(PETSC_HAVE_PARMETIS)
575a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERPARMETIS;
576137cd93aSLisandro Dalcin #elif defined(PETSC_HAVE_PTSCOTCH)
577137cd93aSLisandro Dalcin     *defaultType = PETSCPARTITIONERPTSCOTCH;
578a0058e54SToby Isaac #else
579a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERSIMPLE;
580a0058e54SToby Isaac #endif
581a0058e54SToby Isaac   } else {
582a0058e54SToby Isaac     *defaultType = currentType;
583a0058e54SToby Isaac   }
584a0058e54SToby Isaac   PetscFunctionReturn(0);
585a0058e54SToby Isaac }
586a0058e54SToby Isaac 
58777623264SMatthew G. Knepley /*@
58877623264SMatthew G. Knepley   PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database
58977623264SMatthew G. Knepley 
59077623264SMatthew G. Knepley   Collective on PetscPartitioner
59177623264SMatthew G. Knepley 
59277623264SMatthew G. Knepley   Input Parameter:
59377623264SMatthew G. Knepley . part - the PetscPartitioner object to set options for
59477623264SMatthew G. Knepley 
59577623264SMatthew G. Knepley   Level: developer
59677623264SMatthew G. Knepley 
59777623264SMatthew G. Knepley .seealso: PetscPartitionerView()
59877623264SMatthew G. Knepley @*/
59977623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part)
60077623264SMatthew G. Knepley {
6016bb9daa8SLisandro Dalcin   const char    *defaultType;
6026bb9daa8SLisandro Dalcin   char           name[256];
6036bb9daa8SLisandro Dalcin   PetscBool      flg;
60477623264SMatthew G. Knepley   PetscErrorCode ierr;
60577623264SMatthew G. Knepley 
60677623264SMatthew G. Knepley   PetscFunctionBegin;
60777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
6086bb9daa8SLisandro Dalcin   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
6096bb9daa8SLisandro Dalcin   ierr = PetscPartitionerGetDefaultType(((PetscObject) part)->type_name,&defaultType);CHKERRQ(ierr);
61077623264SMatthew G. Knepley   ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr);
6116bb9daa8SLisandro Dalcin   ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, sizeof(name), &flg);CHKERRQ(ierr);
6126bb9daa8SLisandro Dalcin   if (flg) {
6136bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr);
6146bb9daa8SLisandro Dalcin   } else if (!((PetscObject) part)->type_name) {
6156bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr);
6166bb9daa8SLisandro Dalcin   }
6176bb9daa8SLisandro Dalcin   if (part->ops->setfromoptions) {
6186bb9daa8SLisandro Dalcin     ierr = (*part->ops->setfromoptions)(PetscOptionsObject,part);CHKERRQ(ierr);
6196bb9daa8SLisandro Dalcin   }
620783e1fb6SStefano Zampini   ierr = PetscViewerDestroy(&part->viewerGraph);CHKERRQ(ierr);
6210358368aSMatthew G. Knepley   ierr = PetscOptionsGetViewer(((PetscObject) part)->comm, ((PetscObject) part)->options, ((PetscObject) part)->prefix, "-petscpartitioner_view_graph", &part->viewerGraph, &part->formatGraph, &part->viewGraph);CHKERRQ(ierr);
62277623264SMatthew G. Knepley   /* process any options handlers added with PetscObjectAddOptionsHandler() */
6230633abcbSJed Brown   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) part);CHKERRQ(ierr);
62477623264SMatthew G. Knepley   ierr = PetscOptionsEnd();CHKERRQ(ierr);
62577623264SMatthew G. Knepley   PetscFunctionReturn(0);
62677623264SMatthew G. Knepley }
62777623264SMatthew G. Knepley 
62877623264SMatthew G. Knepley /*@C
62977623264SMatthew G. Knepley   PetscPartitionerSetUp - Construct data structures for the PetscPartitioner
63077623264SMatthew G. Knepley 
63177623264SMatthew G. Knepley   Collective on PetscPartitioner
63277623264SMatthew G. Knepley 
63377623264SMatthew G. Knepley   Input Parameter:
63477623264SMatthew G. Knepley . part - the PetscPartitioner object to setup
63577623264SMatthew G. Knepley 
63677623264SMatthew G. Knepley   Level: developer
63777623264SMatthew G. Knepley 
63877623264SMatthew G. Knepley .seealso: PetscPartitionerView(), PetscPartitionerDestroy()
63977623264SMatthew G. Knepley @*/
64077623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part)
64177623264SMatthew G. Knepley {
64277623264SMatthew G. Knepley   PetscErrorCode ierr;
64377623264SMatthew G. Knepley 
64477623264SMatthew G. Knepley   PetscFunctionBegin;
64577623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
64677623264SMatthew G. Knepley   if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);}
64777623264SMatthew G. Knepley   PetscFunctionReturn(0);
64877623264SMatthew G. Knepley }
64977623264SMatthew G. Knepley 
65077623264SMatthew G. Knepley /*@
65177623264SMatthew G. Knepley   PetscPartitionerDestroy - Destroys a PetscPartitioner object
65277623264SMatthew G. Knepley 
65377623264SMatthew G. Knepley   Collective on PetscPartitioner
65477623264SMatthew G. Knepley 
65577623264SMatthew G. Knepley   Input Parameter:
65677623264SMatthew G. Knepley . part - the PetscPartitioner object to destroy
65777623264SMatthew G. Knepley 
65877623264SMatthew G. Knepley   Level: developer
65977623264SMatthew G. Knepley 
66077623264SMatthew G. Knepley .seealso: PetscPartitionerView()
66177623264SMatthew G. Knepley @*/
66277623264SMatthew G. Knepley PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part)
66377623264SMatthew G. Knepley {
66477623264SMatthew G. Knepley   PetscErrorCode ierr;
66577623264SMatthew G. Knepley 
66677623264SMatthew G. Knepley   PetscFunctionBegin;
66777623264SMatthew G. Knepley   if (!*part) PetscFunctionReturn(0);
66877623264SMatthew G. Knepley   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
66977623264SMatthew G. Knepley 
67077623264SMatthew G. Knepley   if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);}
67177623264SMatthew G. Knepley   ((PetscObject) (*part))->refct = 0;
67277623264SMatthew G. Knepley 
6730358368aSMatthew G. Knepley   ierr = PetscViewerDestroy(&(*part)->viewerGraph);CHKERRQ(ierr);
67477623264SMatthew G. Knepley   if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);}
67577623264SMatthew G. Knepley   ierr = PetscHeaderDestroy(part);CHKERRQ(ierr);
67677623264SMatthew G. Knepley   PetscFunctionReturn(0);
67777623264SMatthew G. Knepley }
67877623264SMatthew G. Knepley 
67977623264SMatthew G. Knepley /*@
68077623264SMatthew G. Knepley   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
68177623264SMatthew G. Knepley 
68277623264SMatthew G. Knepley   Collective on MPI_Comm
68377623264SMatthew G. Knepley 
68477623264SMatthew G. Knepley   Input Parameter:
68577623264SMatthew G. Knepley . comm - The communicator for the PetscPartitioner object
68677623264SMatthew G. Knepley 
68777623264SMatthew G. Knepley   Output Parameter:
68877623264SMatthew G. Knepley . part - The PetscPartitioner object
68977623264SMatthew G. Knepley 
69077623264SMatthew G. Knepley   Level: beginner
69177623264SMatthew G. Knepley 
692dae52e14SToby Isaac .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL, PETSCPARTITIONERSIMPLE, PETSCPARTITIONERGATHER
69377623264SMatthew G. Knepley @*/
69477623264SMatthew G. Knepley PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
69577623264SMatthew G. Knepley {
69677623264SMatthew G. Knepley   PetscPartitioner p;
697a0058e54SToby Isaac   const char       *partitionerType = NULL;
69877623264SMatthew G. Knepley   PetscErrorCode   ierr;
69977623264SMatthew G. Knepley 
70077623264SMatthew G. Knepley   PetscFunctionBegin;
70177623264SMatthew G. Knepley   PetscValidPointer(part, 2);
70277623264SMatthew G. Knepley   *part = NULL;
70383cde681SMatthew G. Knepley   ierr = DMInitializePackage();CHKERRQ(ierr);
70477623264SMatthew G. Knepley 
70573107ff1SLisandro Dalcin   ierr = PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr);
706a0058e54SToby Isaac   ierr = PetscPartitionerGetDefaultType(NULL,&partitionerType);CHKERRQ(ierr);
707a0058e54SToby Isaac   ierr = PetscPartitionerSetType(p,partitionerType);CHKERRQ(ierr);
70877623264SMatthew G. Knepley 
70972379da4SMatthew G. Knepley   p->edgeCut = 0;
71072379da4SMatthew G. Knepley   p->balance = 0.0;
71172379da4SMatthew G. Knepley 
71277623264SMatthew G. Knepley   *part = p;
71377623264SMatthew G. Knepley   PetscFunctionReturn(0);
71477623264SMatthew G. Knepley }
71577623264SMatthew G. Knepley 
71677623264SMatthew G. Knepley /*@
71777623264SMatthew G. Knepley   PetscPartitionerPartition - Create a non-overlapping partition of the cells in the mesh
71877623264SMatthew G. Knepley 
71977623264SMatthew G. Knepley   Collective on DM
72077623264SMatthew G. Knepley 
72177623264SMatthew G. Knepley   Input Parameters:
72277623264SMatthew G. Knepley + part    - The PetscPartitioner
723f8987ae8SMichael Lange - dm      - The mesh DM
72477623264SMatthew G. Knepley 
72577623264SMatthew G. Knepley   Output Parameters:
72677623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
727f8987ae8SMichael Lange - partition       - The list of points by partition
72877623264SMatthew G. Knepley 
7290358368aSMatthew G. Knepley   Options Database:
7300358368aSMatthew G. Knepley . -petscpartitioner_view_graph - View the graph we are partitioning
7310358368aSMatthew G. Knepley 
73277623264SMatthew G. Knepley   Note: Instead of cells, points at a given height can be partitioned by calling PetscPartitionerSetPointHeight()
73377623264SMatthew G. Knepley 
73477623264SMatthew G. Knepley   Level: developer
73577623264SMatthew G. Knepley 
73677623264SMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerSetPointHeight(), PetscPartitionerCreate()
7374b15ede2SMatthew G. Knepley @*/
738f8987ae8SMichael Lange PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, DM dm, PetscSection partSection, IS *partition)
73977623264SMatthew G. Knepley {
74077623264SMatthew G. Knepley   PetscMPIInt    size;
74177623264SMatthew G. Knepley   PetscErrorCode ierr;
74277623264SMatthew G. Knepley 
74377623264SMatthew G. Knepley   PetscFunctionBegin;
74477623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
74577623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
74677623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
74777623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
74877623264SMatthew G. Knepley   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
74977623264SMatthew G. Knepley   if (size == 1) {
75077623264SMatthew G. Knepley     PetscInt *points;
75177623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
75277623264SMatthew G. Knepley 
75377623264SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
75477623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr);
75577623264SMatthew G. Knepley     ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr);
75677623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
75777623264SMatthew G. Knepley     ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr);
75877623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
75977623264SMatthew G. Knepley     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
76077623264SMatthew G. Knepley     PetscFunctionReturn(0);
76177623264SMatthew G. Knepley   }
76277623264SMatthew G. Knepley   if (part->height == 0) {
76377623264SMatthew G. Knepley     PetscInt numVertices;
76477623264SMatthew G. Knepley     PetscInt *start     = NULL;
76577623264SMatthew G. Knepley     PetscInt *adjacency = NULL;
7663fa7752dSToby Isaac     IS       globalNumbering;
76777623264SMatthew G. Knepley 
7683fa7752dSToby Isaac     ierr = DMPlexCreatePartitionerGraph(dm, 0, &numVertices, &start, &adjacency, &globalNumbering);CHKERRQ(ierr);
7690358368aSMatthew G. Knepley     if (part->viewGraph) {
7700358368aSMatthew G. Knepley       PetscViewer viewer = part->viewerGraph;
7710358368aSMatthew G. Knepley       PetscBool   isascii;
7720358368aSMatthew G. Knepley       PetscInt    v, i;
7730358368aSMatthew G. Knepley       PetscMPIInt rank;
7740358368aSMatthew G. Knepley 
7750358368aSMatthew G. Knepley       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) viewer), &rank);CHKERRQ(ierr);
7760358368aSMatthew G. Knepley       ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
7770358368aSMatthew G. Knepley       if (isascii) {
7780358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
7790358368aSMatthew G. Knepley         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %D\n", rank, numVertices);CHKERRQ(ierr);
7800358368aSMatthew G. Knepley         for (v = 0; v < numVertices; ++v) {
7810358368aSMatthew G. Knepley           const PetscInt s = start[v];
7820358368aSMatthew G. Knepley           const PetscInt e = start[v+1];
7830358368aSMatthew G. Knepley 
7840358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]  ", rank);CHKERRQ(ierr);
7850358368aSMatthew G. Knepley           for (i = s; i < e; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%D ", adjacency[i]);CHKERRQ(ierr);}
7860358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D-%D)\n", s, e);CHKERRQ(ierr);
7870358368aSMatthew G. Knepley         }
7880358368aSMatthew G. Knepley         ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
7890358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
7900358368aSMatthew G. Knepley       }
7910358368aSMatthew G. Knepley     }
79277623264SMatthew G. Knepley     if (!part->ops->partition) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONGSTATE, "PetscPartitioner has no type");
79377623264SMatthew G. Knepley     ierr = (*part->ops->partition)(part, dm, size, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
79477623264SMatthew G. Knepley     ierr = PetscFree(start);CHKERRQ(ierr);
79577623264SMatthew G. Knepley     ierr = PetscFree(adjacency);CHKERRQ(ierr);
7963fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
7973fa7752dSToby Isaac       const PetscInt *globalNum;
7983fa7752dSToby Isaac       const PetscInt *partIdx;
7993fa7752dSToby Isaac       PetscInt *map, cStart, cEnd;
8003fa7752dSToby Isaac       PetscInt *adjusted, i, localSize, offset;
8013fa7752dSToby Isaac       IS    newPartition;
8023fa7752dSToby Isaac 
8033fa7752dSToby Isaac       ierr = ISGetLocalSize(*partition,&localSize);CHKERRQ(ierr);
8043fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&adjusted);CHKERRQ(ierr);
8053fa7752dSToby Isaac       ierr = ISGetIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
8063fa7752dSToby Isaac       ierr = ISGetIndices(*partition,&partIdx);CHKERRQ(ierr);
8073fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&map);CHKERRQ(ierr);
8083fa7752dSToby Isaac       ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
8093fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
8103fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
8113fa7752dSToby Isaac       }
8123fa7752dSToby Isaac       for (i = 0; i < localSize; i++) {
8133fa7752dSToby Isaac         adjusted[i] = map[partIdx[i]];
8143fa7752dSToby Isaac       }
8153fa7752dSToby Isaac       ierr = PetscFree(map);CHKERRQ(ierr);
8163fa7752dSToby Isaac       ierr = ISRestoreIndices(*partition,&partIdx);CHKERRQ(ierr);
8173fa7752dSToby Isaac       ierr = ISRestoreIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
8183fa7752dSToby Isaac       ierr = ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition);CHKERRQ(ierr);
8193fa7752dSToby Isaac       ierr = ISDestroy(&globalNumbering);CHKERRQ(ierr);
8203fa7752dSToby Isaac       ierr = ISDestroy(partition);CHKERRQ(ierr);
8213fa7752dSToby Isaac       *partition = newPartition;
8223fa7752dSToby Isaac     }
82377623264SMatthew G. Knepley   } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
8242abdaa70SMatthew G. Knepley   ierr = PetscPartitionerViewFromOptions(part, NULL, "-petscpartitioner_view");CHKERRQ(ierr);
82577623264SMatthew G. Knepley   PetscFunctionReturn(0);
82677623264SMatthew G. Knepley }
82777623264SMatthew G. Knepley 
828d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part)
82977623264SMatthew G. Knepley {
83077623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
83177623264SMatthew G. Knepley   PetscErrorCode          ierr;
83277623264SMatthew G. Knepley 
83377623264SMatthew G. Knepley   PetscFunctionBegin;
83477623264SMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
83577623264SMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
83677623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
83777623264SMatthew G. Knepley   PetscFunctionReturn(0);
83877623264SMatthew G. Knepley }
83977623264SMatthew G. Knepley 
840d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer)
84177623264SMatthew G. Knepley {
842077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
84377623264SMatthew G. Knepley   PetscErrorCode          ierr;
84477623264SMatthew G. Knepley 
84577623264SMatthew G. Knepley   PetscFunctionBegin;
846077101c0SMatthew G. Knepley   if (p->random) {
847077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
848077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "using random partition\n");CHKERRQ(ierr);
849077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
850077101c0SMatthew G. Knepley   }
85177623264SMatthew G. Knepley   PetscFunctionReturn(0);
85277623264SMatthew G. Knepley }
85377623264SMatthew G. Knepley 
854d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer)
85577623264SMatthew G. Knepley {
85677623264SMatthew G. Knepley   PetscBool      iascii;
85777623264SMatthew G. Knepley   PetscErrorCode ierr;
85877623264SMatthew G. Knepley 
85977623264SMatthew G. Knepley   PetscFunctionBegin;
86077623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
86177623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
86277623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
86377623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);}
86477623264SMatthew G. Knepley   PetscFunctionReturn(0);
86577623264SMatthew G. Knepley }
86677623264SMatthew G. Knepley 
867d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerSetFromOptions_Shell(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
868077101c0SMatthew G. Knepley {
869077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
870077101c0SMatthew G. Knepley   PetscErrorCode          ierr;
871077101c0SMatthew G. Knepley 
872077101c0SMatthew G. Knepley   PetscFunctionBegin;
873077101c0SMatthew G. Knepley   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner Shell Options");CHKERRQ(ierr);
874077101c0SMatthew G. Knepley   ierr = PetscOptionsBool("-petscpartitioner_shell_random", "Use a random partition", "PetscPartitionerView", PETSC_FALSE, &p->random, NULL);CHKERRQ(ierr);
875077101c0SMatthew G. Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
876077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
877077101c0SMatthew G. Knepley }
878077101c0SMatthew G. Knepley 
879d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
88077623264SMatthew G. Knepley {
88177623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
88277623264SMatthew G. Knepley   PetscInt                np;
88377623264SMatthew G. Knepley   PetscErrorCode          ierr;
88477623264SMatthew G. Knepley 
88577623264SMatthew G. Knepley   PetscFunctionBegin;
886077101c0SMatthew G. Knepley   if (p->random) {
887077101c0SMatthew G. Knepley     PetscRandom r;
888aa1d5631SMatthew G. Knepley     PetscInt   *sizes, *points, v, p;
889aa1d5631SMatthew G. Knepley     PetscMPIInt rank;
890077101c0SMatthew G. Knepley 
891aa1d5631SMatthew G. Knepley     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
892077101c0SMatthew G. Knepley     ierr = PetscRandomCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr);
893c717d290SMatthew G. Knepley     ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) nparts);CHKERRQ(ierr);
894077101c0SMatthew G. Knepley     ierr = PetscRandomSetFromOptions(r);CHKERRQ(ierr);
895077101c0SMatthew G. Knepley     ierr = PetscCalloc2(nparts, &sizes, numVertices, &points);CHKERRQ(ierr);
896aa1d5631SMatthew G. Knepley     for (v = 0; v < numVertices; ++v) {points[v] = v;}
897ac9a96f1SMichael Lange     for (p = 0; p < nparts; ++p) {sizes[p] = numVertices/nparts + (PetscInt) (p < numVertices % nparts);}
898aa1d5631SMatthew G. Knepley     for (v = numVertices-1; v > 0; --v) {
899077101c0SMatthew G. Knepley       PetscReal val;
900aa1d5631SMatthew G. Knepley       PetscInt  w, tmp;
901077101c0SMatthew G. Knepley 
902aa1d5631SMatthew G. Knepley       ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) (v+1));CHKERRQ(ierr);
903077101c0SMatthew G. Knepley       ierr = PetscRandomGetValueReal(r, &val);CHKERRQ(ierr);
904aa1d5631SMatthew G. Knepley       w    = PetscFloorReal(val);
905aa1d5631SMatthew G. Knepley       tmp       = points[v];
906aa1d5631SMatthew G. Knepley       points[v] = points[w];
907aa1d5631SMatthew G. Knepley       points[w] = tmp;
908077101c0SMatthew G. Knepley     }
909077101c0SMatthew G. Knepley     ierr = PetscRandomDestroy(&r);CHKERRQ(ierr);
910077101c0SMatthew G. Knepley     ierr = PetscPartitionerShellSetPartition(part, nparts, sizes, points);CHKERRQ(ierr);
911077101c0SMatthew G. Knepley     ierr = PetscFree2(sizes, points);CHKERRQ(ierr);
912077101c0SMatthew G. Knepley   }
913c717d290SMatthew G. Knepley   if (!p->section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Shell partitioner information not provided. Please call PetscPartitionerShellSetPartition()");
91477623264SMatthew G. Knepley   ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr);
91577623264SMatthew G. Knepley   if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np);
91677623264SMatthew G. Knepley   ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr);
91777623264SMatthew G. Knepley   if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np);
9185680f57bSMatthew G. Knepley   ierr = PetscSectionCopy(p->section, partSection);CHKERRQ(ierr);
91977623264SMatthew G. Knepley   *partition = p->partition;
92077623264SMatthew G. Knepley   ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr);
92177623264SMatthew G. Knepley   PetscFunctionReturn(0);
92277623264SMatthew G. Knepley }
92377623264SMatthew G. Knepley 
924d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part)
92577623264SMatthew G. Knepley {
92677623264SMatthew G. Knepley   PetscFunctionBegin;
92777623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_Shell;
928077101c0SMatthew G. Knepley   part->ops->setfromoptions = PetscPartitionerSetFromOptions_Shell;
92977623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_Shell;
93077623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_Shell;
93177623264SMatthew G. Knepley   PetscFunctionReturn(0);
93277623264SMatthew G. Knepley }
93377623264SMatthew G. Knepley 
93477623264SMatthew G. Knepley /*MC
93577623264SMatthew G. Knepley   PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object
93677623264SMatthew G. Knepley 
93777623264SMatthew G. Knepley   Level: intermediate
93877623264SMatthew G. Knepley 
93977623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
94077623264SMatthew G. Knepley M*/
94177623264SMatthew G. Knepley 
94277623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part)
94377623264SMatthew G. Knepley {
94477623264SMatthew G. Knepley   PetscPartitioner_Shell *p;
94577623264SMatthew G. Knepley   PetscErrorCode          ierr;
94677623264SMatthew G. Knepley 
94777623264SMatthew G. Knepley   PetscFunctionBegin;
94877623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
94977623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
95077623264SMatthew G. Knepley   part->data = p;
95177623264SMatthew G. Knepley 
95277623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr);
953077101c0SMatthew G. Knepley   p->random = PETSC_FALSE;
95477623264SMatthew G. Knepley   PetscFunctionReturn(0);
95577623264SMatthew G. Knepley }
95677623264SMatthew G. Knepley 
9575680f57bSMatthew G. Knepley /*@C
9585680f57bSMatthew G. Knepley   PetscPartitionerShellSetPartition - Set an artifical partition for a mesh
9595680f57bSMatthew G. Knepley 
960077101c0SMatthew G. Knepley   Collective on Part
9615680f57bSMatthew G. Knepley 
9625680f57bSMatthew G. Knepley   Input Parameters:
9635680f57bSMatthew G. Knepley + part     - The PetscPartitioner
9649852e123SBarry Smith . size - The number of partitions
9659852e123SBarry Smith . sizes    - array of size size (or NULL) providing the number of points in each partition
9669758bf69SToby 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.)
9675680f57bSMatthew G. Knepley 
9685680f57bSMatthew G. Knepley   Level: developer
9695680f57bSMatthew G. Knepley 
970b7e49471SLawrence Mitchell   Notes:
971b7e49471SLawrence Mitchell 
972b7e49471SLawrence Mitchell     It is safe to free the sizes and points arrays after use in this routine.
973b7e49471SLawrence Mitchell 
9745680f57bSMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerCreate()
9755680f57bSMatthew G. Knepley @*/
9769852e123SBarry Smith PetscErrorCode PetscPartitionerShellSetPartition(PetscPartitioner part, PetscInt size, const PetscInt sizes[], const PetscInt points[])
9775680f57bSMatthew G. Knepley {
9785680f57bSMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
9795680f57bSMatthew G. Knepley   PetscInt                proc, numPoints;
9805680f57bSMatthew G. Knepley   PetscErrorCode          ierr;
9815680f57bSMatthew G. Knepley 
9825680f57bSMatthew G. Knepley   PetscFunctionBegin;
9835680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
9845680f57bSMatthew G. Knepley   if (sizes)  {PetscValidPointer(sizes, 3);}
985c717d290SMatthew G. Knepley   if (points) {PetscValidPointer(points, 4);}
9865680f57bSMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
9875680f57bSMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
9885680f57bSMatthew G. Knepley   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) part), &p->section);CHKERRQ(ierr);
9899852e123SBarry Smith   ierr = PetscSectionSetChart(p->section, 0, size);CHKERRQ(ierr);
9905680f57bSMatthew G. Knepley   if (sizes) {
9919852e123SBarry Smith     for (proc = 0; proc < size; ++proc) {
9925680f57bSMatthew G. Knepley       ierr = PetscSectionSetDof(p->section, proc, sizes[proc]);CHKERRQ(ierr);
9935680f57bSMatthew G. Knepley     }
9945680f57bSMatthew G. Knepley   }
9955680f57bSMatthew G. Knepley   ierr = PetscSectionSetUp(p->section);CHKERRQ(ierr);
9965680f57bSMatthew G. Knepley   ierr = PetscSectionGetStorageSize(p->section, &numPoints);CHKERRQ(ierr);
9975680f57bSMatthew G. Knepley   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), numPoints, points, PETSC_COPY_VALUES, &p->partition);CHKERRQ(ierr);
9985680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
9995680f57bSMatthew G. Knepley }
10005680f57bSMatthew G. Knepley 
1001077101c0SMatthew G. Knepley /*@
1002077101c0SMatthew G. Knepley   PetscPartitionerShellSetRandom - Set the flag to use a random partition
1003077101c0SMatthew G. Knepley 
1004077101c0SMatthew G. Knepley   Collective on Part
1005077101c0SMatthew G. Knepley 
1006077101c0SMatthew G. Knepley   Input Parameters:
1007077101c0SMatthew G. Knepley + part   - The PetscPartitioner
1008077101c0SMatthew G. Knepley - random - The flag to use a random partition
1009077101c0SMatthew G. Knepley 
1010077101c0SMatthew G. Knepley   Level: intermediate
1011077101c0SMatthew G. Knepley 
1012077101c0SMatthew G. Knepley .seealso PetscPartitionerShellGetRandom(), PetscPartitionerCreate()
1013077101c0SMatthew G. Knepley @*/
1014077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellSetRandom(PetscPartitioner part, PetscBool random)
1015077101c0SMatthew G. Knepley {
1016077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1017077101c0SMatthew G. Knepley 
1018077101c0SMatthew G. Knepley   PetscFunctionBegin;
1019077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1020077101c0SMatthew G. Knepley   p->random = random;
1021077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1022077101c0SMatthew G. Knepley }
1023077101c0SMatthew G. Knepley 
1024077101c0SMatthew G. Knepley /*@
1025077101c0SMatthew G. Knepley   PetscPartitionerShellGetRandom - get the flag to use a random partition
1026077101c0SMatthew G. Knepley 
1027077101c0SMatthew G. Knepley   Collective on Part
1028077101c0SMatthew G. Knepley 
1029077101c0SMatthew G. Knepley   Input Parameter:
1030077101c0SMatthew G. Knepley . part   - The PetscPartitioner
1031077101c0SMatthew G. Knepley 
1032077101c0SMatthew G. Knepley   Output Parameter
1033077101c0SMatthew G. Knepley . random - The flag to use a random partition
1034077101c0SMatthew G. Knepley 
1035077101c0SMatthew G. Knepley   Level: intermediate
1036077101c0SMatthew G. Knepley 
1037077101c0SMatthew G. Knepley .seealso PetscPartitionerShellSetRandom(), PetscPartitionerCreate()
1038077101c0SMatthew G. Knepley @*/
1039077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellGetRandom(PetscPartitioner part, PetscBool *random)
1040077101c0SMatthew G. Knepley {
1041077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1042077101c0SMatthew G. Knepley 
1043077101c0SMatthew G. Knepley   PetscFunctionBegin;
1044077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1045077101c0SMatthew G. Knepley   PetscValidPointer(random, 2);
1046077101c0SMatthew G. Knepley   *random = p->random;
1047077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1048077101c0SMatthew G. Knepley }
1049077101c0SMatthew G. Knepley 
1050d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Simple(PetscPartitioner part)
1051555a9cf8SMatthew G. Knepley {
1052555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p = (PetscPartitioner_Simple *) part->data;
1053555a9cf8SMatthew G. Knepley   PetscErrorCode          ierr;
1054555a9cf8SMatthew G. Knepley 
1055555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1056555a9cf8SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
1057555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1058555a9cf8SMatthew G. Knepley }
1059555a9cf8SMatthew G. Knepley 
1060d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple_Ascii(PetscPartitioner part, PetscViewer viewer)
1061555a9cf8SMatthew G. Knepley {
1062555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1063555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1064555a9cf8SMatthew G. Knepley }
1065555a9cf8SMatthew G. Knepley 
1066d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple(PetscPartitioner part, PetscViewer viewer)
1067555a9cf8SMatthew G. Knepley {
1068555a9cf8SMatthew G. Knepley   PetscBool      iascii;
1069555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1070555a9cf8SMatthew G. Knepley 
1071555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1072555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1073555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1074555a9cf8SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1075555a9cf8SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Simple_Ascii(part, viewer);CHKERRQ(ierr);}
1076555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1077555a9cf8SMatthew G. Knepley }
1078555a9cf8SMatthew G. Knepley 
1079d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Simple(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1080555a9cf8SMatthew G. Knepley {
1081cead94edSToby Isaac   MPI_Comm       comm;
1082555a9cf8SMatthew G. Knepley   PetscInt       np;
1083cead94edSToby Isaac   PetscMPIInt    size;
1084555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1085555a9cf8SMatthew G. Knepley 
1086555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
108704ba2274SStefano Zampini   comm = PetscObjectComm((PetscObject)part);
1088cead94edSToby Isaac   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1089555a9cf8SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1090555a9cf8SMatthew G. Knepley   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1091cead94edSToby Isaac   if (size == 1) {
1092cead94edSToby Isaac     for (np = 0; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, numVertices/nparts + ((numVertices % nparts) > np));CHKERRQ(ierr);}
109304ba2274SStefano Zampini   } else {
1094cead94edSToby Isaac     PetscMPIInt rank;
1095cead94edSToby Isaac     PetscInt nvGlobal, *offsets, myFirst, myLast;
1096cead94edSToby Isaac 
1097a679a563SToby Isaac     ierr = PetscMalloc1(size+1,&offsets);CHKERRQ(ierr);
1098cead94edSToby Isaac     offsets[0] = 0;
1099cead94edSToby Isaac     ierr = MPI_Allgather(&numVertices,1,MPIU_INT,&offsets[1],1,MPIU_INT,comm);CHKERRQ(ierr);
1100cead94edSToby Isaac     for (np = 2; np <= size; np++) {
1101cead94edSToby Isaac       offsets[np] += offsets[np-1];
1102cead94edSToby Isaac     }
1103cead94edSToby Isaac     nvGlobal = offsets[size];
1104cead94edSToby Isaac     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1105cead94edSToby Isaac     myFirst = offsets[rank];
1106cead94edSToby Isaac     myLast  = offsets[rank + 1] - 1;
1107cead94edSToby Isaac     ierr = PetscFree(offsets);CHKERRQ(ierr);
1108cead94edSToby Isaac     if (numVertices) {
1109cead94edSToby Isaac       PetscInt firstPart = 0, firstLargePart = 0;
1110cead94edSToby Isaac       PetscInt lastPart = 0, lastLargePart = 0;
1111cead94edSToby Isaac       PetscInt rem = nvGlobal % nparts;
1112cead94edSToby Isaac       PetscInt pSmall = nvGlobal/nparts;
1113cead94edSToby Isaac       PetscInt pBig = nvGlobal/nparts + 1;
1114cead94edSToby Isaac 
1115cead94edSToby Isaac 
1116cead94edSToby Isaac       if (rem) {
1117cead94edSToby Isaac         firstLargePart = myFirst / pBig;
1118cead94edSToby Isaac         lastLargePart  = myLast  / pBig;
1119cead94edSToby Isaac 
1120cead94edSToby Isaac         if (firstLargePart < rem) {
1121cead94edSToby Isaac           firstPart = firstLargePart;
112204ba2274SStefano Zampini         } else {
1123cead94edSToby Isaac           firstPart = rem + (myFirst - (rem * pBig)) / pSmall;
1124cead94edSToby Isaac         }
1125cead94edSToby Isaac         if (lastLargePart < rem) {
1126cead94edSToby Isaac           lastPart = lastLargePart;
112704ba2274SStefano Zampini         } else {
1128cead94edSToby Isaac           lastPart = rem + (myLast - (rem * pBig)) / pSmall;
1129cead94edSToby Isaac         }
113004ba2274SStefano Zampini       } else {
1131cead94edSToby Isaac         firstPart = myFirst / (nvGlobal/nparts);
1132cead94edSToby Isaac         lastPart  = myLast  / (nvGlobal/nparts);
1133cead94edSToby Isaac       }
1134cead94edSToby Isaac 
1135cead94edSToby Isaac       for (np = firstPart; np <= lastPart; np++) {
1136cead94edSToby Isaac         PetscInt PartStart =  np    * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np);
1137cead94edSToby Isaac         PetscInt PartEnd   = (np+1) * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np+1);
1138cead94edSToby Isaac 
1139cead94edSToby Isaac         PartStart = PetscMax(PartStart,myFirst);
1140cead94edSToby Isaac         PartEnd   = PetscMin(PartEnd,myLast+1);
1141cead94edSToby Isaac         ierr = PetscSectionSetDof(partSection,np,PartEnd-PartStart);CHKERRQ(ierr);
1142cead94edSToby Isaac       }
1143cead94edSToby Isaac     }
1144cead94edSToby Isaac   }
1145cead94edSToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1146555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1147555a9cf8SMatthew G. Knepley }
1148555a9cf8SMatthew G. Knepley 
1149d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Simple(PetscPartitioner part)
1150555a9cf8SMatthew G. Knepley {
1151555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1152555a9cf8SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Simple;
1153555a9cf8SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Simple;
1154555a9cf8SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Simple;
1155555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1156555a9cf8SMatthew G. Knepley }
1157555a9cf8SMatthew G. Knepley 
1158555a9cf8SMatthew G. Knepley /*MC
1159555a9cf8SMatthew G. Knepley   PETSCPARTITIONERSIMPLE = "simple" - A PetscPartitioner object
1160555a9cf8SMatthew G. Knepley 
1161555a9cf8SMatthew G. Knepley   Level: intermediate
1162555a9cf8SMatthew G. Knepley 
1163555a9cf8SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1164555a9cf8SMatthew G. Knepley M*/
1165555a9cf8SMatthew G. Knepley 
1166555a9cf8SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Simple(PetscPartitioner part)
1167555a9cf8SMatthew G. Knepley {
1168555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p;
1169555a9cf8SMatthew G. Knepley   PetscErrorCode           ierr;
1170555a9cf8SMatthew G. Knepley 
1171555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1172555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1173555a9cf8SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1174555a9cf8SMatthew G. Knepley   part->data = p;
1175555a9cf8SMatthew G. Knepley 
1176555a9cf8SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Simple(part);CHKERRQ(ierr);
1177555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1178555a9cf8SMatthew G. Knepley }
1179555a9cf8SMatthew G. Knepley 
1180d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Gather(PetscPartitioner part)
1181dae52e14SToby Isaac {
1182dae52e14SToby Isaac   PetscPartitioner_Gather *p = (PetscPartitioner_Gather *) part->data;
1183dae52e14SToby Isaac   PetscErrorCode          ierr;
1184dae52e14SToby Isaac 
1185dae52e14SToby Isaac   PetscFunctionBegin;
1186dae52e14SToby Isaac   ierr = PetscFree(p);CHKERRQ(ierr);
1187dae52e14SToby Isaac   PetscFunctionReturn(0);
1188dae52e14SToby Isaac }
1189dae52e14SToby Isaac 
1190d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather_Ascii(PetscPartitioner part, PetscViewer viewer)
1191dae52e14SToby Isaac {
1192dae52e14SToby Isaac   PetscFunctionBegin;
1193dae52e14SToby Isaac   PetscFunctionReturn(0);
1194dae52e14SToby Isaac }
1195dae52e14SToby Isaac 
1196d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather(PetscPartitioner part, PetscViewer viewer)
1197dae52e14SToby Isaac {
1198dae52e14SToby Isaac   PetscBool      iascii;
1199dae52e14SToby Isaac   PetscErrorCode ierr;
1200dae52e14SToby Isaac 
1201dae52e14SToby Isaac   PetscFunctionBegin;
1202dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1203dae52e14SToby Isaac   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1204dae52e14SToby Isaac   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1205dae52e14SToby Isaac   if (iascii) {ierr = PetscPartitionerView_Gather_Ascii(part, viewer);CHKERRQ(ierr);}
1206dae52e14SToby Isaac   PetscFunctionReturn(0);
1207dae52e14SToby Isaac }
1208dae52e14SToby Isaac 
1209d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Gather(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1210dae52e14SToby Isaac {
1211dae52e14SToby Isaac   PetscInt       np;
1212dae52e14SToby Isaac   PetscErrorCode ierr;
1213dae52e14SToby Isaac 
1214dae52e14SToby Isaac   PetscFunctionBegin;
1215dae52e14SToby Isaac   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1216dae52e14SToby Isaac   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1217dae52e14SToby Isaac   ierr = PetscSectionSetDof(partSection,0,numVertices);CHKERRQ(ierr);
1218dae52e14SToby Isaac   for (np = 1; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, 0);CHKERRQ(ierr);}
1219dae52e14SToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1220dae52e14SToby Isaac   PetscFunctionReturn(0);
1221dae52e14SToby Isaac }
1222dae52e14SToby Isaac 
1223d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Gather(PetscPartitioner part)
1224dae52e14SToby Isaac {
1225dae52e14SToby Isaac   PetscFunctionBegin;
1226dae52e14SToby Isaac   part->ops->view      = PetscPartitionerView_Gather;
1227dae52e14SToby Isaac   part->ops->destroy   = PetscPartitionerDestroy_Gather;
1228dae52e14SToby Isaac   part->ops->partition = PetscPartitionerPartition_Gather;
1229dae52e14SToby Isaac   PetscFunctionReturn(0);
1230dae52e14SToby Isaac }
1231dae52e14SToby Isaac 
1232dae52e14SToby Isaac /*MC
1233dae52e14SToby Isaac   PETSCPARTITIONERGATHER = "gather" - A PetscPartitioner object
1234dae52e14SToby Isaac 
1235dae52e14SToby Isaac   Level: intermediate
1236dae52e14SToby Isaac 
1237dae52e14SToby Isaac .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1238dae52e14SToby Isaac M*/
1239dae52e14SToby Isaac 
1240dae52e14SToby Isaac PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Gather(PetscPartitioner part)
1241dae52e14SToby Isaac {
1242dae52e14SToby Isaac   PetscPartitioner_Gather *p;
1243dae52e14SToby Isaac   PetscErrorCode           ierr;
1244dae52e14SToby Isaac 
1245dae52e14SToby Isaac   PetscFunctionBegin;
1246dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1247dae52e14SToby Isaac   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1248dae52e14SToby Isaac   part->data = p;
1249dae52e14SToby Isaac 
1250dae52e14SToby Isaac   ierr = PetscPartitionerInitialize_Gather(part);CHKERRQ(ierr);
1251dae52e14SToby Isaac   PetscFunctionReturn(0);
1252dae52e14SToby Isaac }
1253dae52e14SToby Isaac 
1254dae52e14SToby Isaac 
1255d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part)
125677623264SMatthew G. Knepley {
125777623264SMatthew G. Knepley   PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data;
125877623264SMatthew G. Knepley   PetscErrorCode          ierr;
125977623264SMatthew G. Knepley 
126077623264SMatthew G. Knepley   PetscFunctionBegin;
126177623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
126277623264SMatthew G. Knepley   PetscFunctionReturn(0);
126377623264SMatthew G. Knepley }
126477623264SMatthew G. Knepley 
1265d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer)
126677623264SMatthew G. Knepley {
126777623264SMatthew G. Knepley   PetscFunctionBegin;
126877623264SMatthew G. Knepley   PetscFunctionReturn(0);
126977623264SMatthew G. Knepley }
127077623264SMatthew G. Knepley 
1271d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer)
127277623264SMatthew G. Knepley {
127377623264SMatthew G. Knepley   PetscBool      iascii;
127477623264SMatthew G. Knepley   PetscErrorCode ierr;
127577623264SMatthew G. Knepley 
127677623264SMatthew G. Knepley   PetscFunctionBegin;
127777623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
127877623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
127977623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
128077623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);}
128177623264SMatthew G. Knepley   PetscFunctionReturn(0);
128277623264SMatthew G. Knepley }
128377623264SMatthew G. Knepley 
128470034214SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
128570034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
128670034214SMatthew G. Knepley #include <unistd.h>
128770034214SMatthew G. Knepley #endif
128811d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
128911d1e910SBarry Smith #include <chaco.h>
129011d1e910SBarry Smith #else
129111d1e910SBarry Smith /* Older versions of Chaco do not have an include file */
129270034214SMatthew G. Knepley PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
129370034214SMatthew G. Knepley                        float *ewgts, float *x, float *y, float *z, char *outassignname,
129470034214SMatthew G. Knepley                        char *outfilename, short *assignment, int architecture, int ndims_tot,
129570034214SMatthew G. Knepley                        int mesh_dims[3], double *goal, int global_method, int local_method,
129670034214SMatthew G. Knepley                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
129711d1e910SBarry Smith #endif
129870034214SMatthew G. Knepley extern int FREE_GRAPH;
129977623264SMatthew G. Knepley #endif
130070034214SMatthew G. Knepley 
1301d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
130270034214SMatthew G. Knepley {
130377623264SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
130470034214SMatthew G. Knepley   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
130570034214SMatthew G. Knepley   MPI_Comm       comm;
130670034214SMatthew G. Knepley   int            nvtxs          = numVertices; /* number of vertices in full graph */
130770034214SMatthew G. Knepley   int           *vwgts          = NULL;   /* weights for all vertices */
130870034214SMatthew G. Knepley   float         *ewgts          = NULL;   /* weights for all edges */
130970034214SMatthew G. Knepley   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
131070034214SMatthew G. Knepley   char          *outassignname  = NULL;   /*  name of assignment output file */
131170034214SMatthew G. Knepley   char          *outfilename    = NULL;   /* output file name */
131270034214SMatthew G. Knepley   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
131370034214SMatthew G. Knepley   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
131470034214SMatthew G. Knepley   int            mesh_dims[3];            /* dimensions of mesh of processors */
131570034214SMatthew G. Knepley   double        *goal          = NULL;    /* desired set sizes for each set */
131670034214SMatthew G. Knepley   int            global_method = 1;       /* global partitioning algorithm */
131770034214SMatthew G. Knepley   int            local_method  = 1;       /* local partitioning algorithm */
131870034214SMatthew G. Knepley   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
131970034214SMatthew G. Knepley   int            vmax          = 200;     /* how many vertices to coarsen down to? */
132070034214SMatthew G. Knepley   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
132170034214SMatthew G. Knepley   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
132270034214SMatthew G. Knepley   long           seed          = 123636512; /* for random graph mutations */
132311d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
132411d1e910SBarry Smith   int           *assignment;              /* Output partition */
132511d1e910SBarry Smith #else
132670034214SMatthew G. Knepley   short int     *assignment;              /* Output partition */
132711d1e910SBarry Smith #endif
132870034214SMatthew G. Knepley   int            fd_stdout, fd_pipe[2];
132970034214SMatthew G. Knepley   PetscInt      *points;
133070034214SMatthew G. Knepley   int            i, v, p;
133170034214SMatthew G. Knepley   PetscErrorCode ierr;
133270034214SMatthew G. Knepley 
133370034214SMatthew G. Knepley   PetscFunctionBegin;
133470034214SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
133507ed3857SLisandro Dalcin #if defined (PETSC_USE_DEBUG)
133607ed3857SLisandro Dalcin   {
133707ed3857SLisandro Dalcin     int ival,isum;
133807ed3857SLisandro Dalcin     PetscBool distributed;
133907ed3857SLisandro Dalcin 
134007ed3857SLisandro Dalcin     ival = (numVertices > 0);
134107ed3857SLisandro Dalcin     ierr = MPI_Allreduce(&ival, &isum, 1, MPI_INT, MPI_SUM, comm);CHKERRQ(ierr);
134207ed3857SLisandro Dalcin     distributed = (isum > 1) ? PETSC_TRUE : PETSC_FALSE;
134307ed3857SLisandro Dalcin     if (distributed) SETERRQ(comm, PETSC_ERR_SUP, "Chaco cannot partition a distributed graph");
134407ed3857SLisandro Dalcin   }
134507ed3857SLisandro Dalcin #endif
134670034214SMatthew G. Knepley   if (!numVertices) {
134777623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
134877623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
134970034214SMatthew G. Knepley     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
135070034214SMatthew G. Knepley     PetscFunctionReturn(0);
135170034214SMatthew G. Knepley   }
135270034214SMatthew G. Knepley   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
135370034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
135470034214SMatthew G. Knepley 
135570034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
135670034214SMatthew G. Knepley     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
135770034214SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
135870034214SMatthew G. Knepley   }
135977623264SMatthew G. Knepley   mesh_dims[0] = nparts;
136070034214SMatthew G. Knepley   mesh_dims[1] = 1;
136170034214SMatthew G. Knepley   mesh_dims[2] = 1;
136270034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr);
136370034214SMatthew G. Knepley   /* Chaco outputs to stdout. We redirect this to a buffer. */
136470034214SMatthew G. Knepley   /* TODO: check error codes for UNIX calls */
136570034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
136670034214SMatthew G. Knepley   {
136770034214SMatthew G. Knepley     int piperet;
136870034214SMatthew G. Knepley     piperet = pipe(fd_pipe);
136970034214SMatthew G. Knepley     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
137070034214SMatthew G. Knepley     fd_stdout = dup(1);
137170034214SMatthew G. Knepley     close(1);
137270034214SMatthew G. Knepley     dup2(fd_pipe[1], 1);
137370034214SMatthew G. Knepley   }
137470034214SMatthew G. Knepley #endif
137570034214SMatthew G. Knepley   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
137670034214SMatthew G. Knepley                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
137770034214SMatthew G. Knepley                    vmax, ndims, eigtol, seed);
137870034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
137970034214SMatthew G. Knepley   {
138070034214SMatthew G. Knepley     char msgLog[10000];
138170034214SMatthew G. Knepley     int  count;
138270034214SMatthew G. Knepley 
138370034214SMatthew G. Knepley     fflush(stdout);
138470034214SMatthew G. Knepley     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
138570034214SMatthew G. Knepley     if (count < 0) count = 0;
138670034214SMatthew G. Knepley     msgLog[count] = 0;
138770034214SMatthew G. Knepley     close(1);
138870034214SMatthew G. Knepley     dup2(fd_stdout, 1);
138970034214SMatthew G. Knepley     close(fd_stdout);
139070034214SMatthew G. Knepley     close(fd_pipe[0]);
139170034214SMatthew G. Knepley     close(fd_pipe[1]);
139270034214SMatthew G. Knepley     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
139370034214SMatthew G. Knepley   }
139407ed3857SLisandro Dalcin #else
139507ed3857SLisandro Dalcin   if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", "error in stdout");
139670034214SMatthew G. Knepley #endif
139770034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
139877623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
139970034214SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {
140077623264SMatthew G. Knepley     ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);
140170034214SMatthew G. Knepley   }
140277623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
140370034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
140477623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
140570034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
140670034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
140770034214SMatthew G. Knepley     }
140870034214SMatthew G. Knepley   }
140970034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
141070034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
141170034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
141270034214SMatthew G. Knepley     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
141370034214SMatthew G. Knepley   }
141470034214SMatthew G. Knepley   ierr = PetscFree(assignment);CHKERRQ(ierr);
141570034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
141670034214SMatthew G. Knepley   PetscFunctionReturn(0);
141777623264SMatthew G. Knepley #else
141877623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
141970034214SMatthew G. Knepley #endif
142077623264SMatthew G. Knepley }
142177623264SMatthew G. Knepley 
1422d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part)
142377623264SMatthew G. Knepley {
142477623264SMatthew G. Knepley   PetscFunctionBegin;
142577623264SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Chaco;
142677623264SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Chaco;
142777623264SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Chaco;
142877623264SMatthew G. Knepley   PetscFunctionReturn(0);
142977623264SMatthew G. Knepley }
143077623264SMatthew G. Knepley 
143177623264SMatthew G. Knepley /*MC
143277623264SMatthew G. Knepley   PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library
143377623264SMatthew G. Knepley 
143477623264SMatthew G. Knepley   Level: intermediate
143577623264SMatthew G. Knepley 
143677623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
143777623264SMatthew G. Knepley M*/
143877623264SMatthew G. Knepley 
143977623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part)
144077623264SMatthew G. Knepley {
144177623264SMatthew G. Knepley   PetscPartitioner_Chaco *p;
144277623264SMatthew G. Knepley   PetscErrorCode          ierr;
144377623264SMatthew G. Knepley 
144477623264SMatthew G. Knepley   PetscFunctionBegin;
144577623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
144677623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
144777623264SMatthew G. Knepley   part->data = p;
144877623264SMatthew G. Knepley 
144977623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr);
145077623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr);
145177623264SMatthew G. Knepley   PetscFunctionReturn(0);
145277623264SMatthew G. Knepley }
145377623264SMatthew G. Knepley 
14545b440754SMatthew G. Knepley static const char *ptypes[] = {"kway", "rb"};
14555b440754SMatthew G. Knepley 
1456d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part)
145777623264SMatthew G. Knepley {
145877623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
145977623264SMatthew G. Knepley   PetscErrorCode             ierr;
146077623264SMatthew G. Knepley 
146177623264SMatthew G. Knepley   PetscFunctionBegin;
146277623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
146377623264SMatthew G. Knepley   PetscFunctionReturn(0);
146477623264SMatthew G. Knepley }
146577623264SMatthew G. Knepley 
1466d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer)
146777623264SMatthew G. Knepley {
14682abdaa70SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
146977623264SMatthew G. Knepley   PetscErrorCode             ierr;
147077623264SMatthew G. Knepley 
147177623264SMatthew G. Knepley   PetscFunctionBegin;
14722abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
14732abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "ParMetis type: %s\n", ptypes[p->ptype]);CHKERRQ(ierr);
14742abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "load imbalance ratio %g\n", (double) p->imbalanceRatio);CHKERRQ(ierr);
14752abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "debug flag %D\n", p->debugFlag);CHKERRQ(ierr);
14762abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
147777623264SMatthew G. Knepley   PetscFunctionReturn(0);
147877623264SMatthew G. Knepley }
147977623264SMatthew G. Knepley 
1480d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer)
148177623264SMatthew G. Knepley {
148277623264SMatthew G. Knepley   PetscBool      iascii;
148377623264SMatthew G. Knepley   PetscErrorCode ierr;
148477623264SMatthew G. Knepley 
148577623264SMatthew G. Knepley   PetscFunctionBegin;
148677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
148777623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
148877623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
148977623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);}
149077623264SMatthew G. Knepley   PetscFunctionReturn(0);
149177623264SMatthew G. Knepley }
149270034214SMatthew G. Knepley 
149344d8be81SLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_ParMetis(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
149444d8be81SLisandro Dalcin {
149544d8be81SLisandro Dalcin   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
149642678178SLisandro Dalcin   PetscInt                  p_randomSeed = -1; /* TODO: Add this to PetscPartitioner_ParMetis */
149744d8be81SLisandro Dalcin   PetscErrorCode            ierr;
149844d8be81SLisandro Dalcin 
149944d8be81SLisandro Dalcin   PetscFunctionBegin;
150044d8be81SLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner ParMetis Options");CHKERRQ(ierr);
150144d8be81SLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_parmetis_type", "Partitioning method", "", ptypes, 2, ptypes[p->ptype], &p->ptype, NULL);CHKERRQ(ierr);
15025b440754SMatthew G. Knepley   ierr = PetscOptionsReal("-petscpartitioner_parmetis_imbalance_ratio", "Load imbalance ratio limit", "", p->imbalanceRatio, &p->imbalanceRatio, NULL);CHKERRQ(ierr);
15035b440754SMatthew G. Knepley   ierr = PetscOptionsInt("-petscpartitioner_parmetis_debug", "Debugging flag", "", p->debugFlag, &p->debugFlag, NULL);CHKERRQ(ierr);
150442678178SLisandro Dalcin   ierr = PetscOptionsInt("-petscpartitioner_parmetis_seed", "Random seed", "", p_randomSeed, &p_randomSeed, NULL);CHKERRQ(ierr);
150544d8be81SLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
150644d8be81SLisandro Dalcin   PetscFunctionReturn(0);
150744d8be81SLisandro Dalcin }
150844d8be81SLisandro Dalcin 
150970034214SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
151070034214SMatthew G. Knepley #include <parmetis.h>
151177623264SMatthew G. Knepley #endif
151270034214SMatthew G. Knepley 
1513d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
151470034214SMatthew G. Knepley {
151577623264SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
15165b440754SMatthew G. Knepley   PetscPartitioner_ParMetis *pm = (PetscPartitioner_ParMetis *) part->data;
151770034214SMatthew G. Knepley   MPI_Comm       comm;
1518deea36a5SMatthew G. Knepley   PetscSection   section;
151970034214SMatthew G. Knepley   PetscInt       nvtxs       = numVertices; /* The number of vertices in full graph */
152070034214SMatthew G. Knepley   PetscInt      *vtxdist;                   /* Distribution of vertices across processes */
152170034214SMatthew G. Knepley   PetscInt      *xadj        = start;       /* Start of edge list for each vertex */
152270034214SMatthew G. Knepley   PetscInt      *adjncy      = adjacency;   /* Edge lists for all vertices */
152370034214SMatthew G. Knepley   PetscInt      *vwgt        = NULL;        /* Vertex weights */
152470034214SMatthew G. Knepley   PetscInt      *adjwgt      = NULL;        /* Edge weights */
152570034214SMatthew G. Knepley   PetscInt       wgtflag     = 0;           /* Indicates which weights are present */
152670034214SMatthew G. Knepley   PetscInt       numflag     = 0;           /* Indicates initial offset (0 or 1) */
152770034214SMatthew G. Knepley   PetscInt       ncon        = 1;           /* The number of weights per vertex */
15285b440754SMatthew G. Knepley   PetscInt       metis_ptype = pm->ptype;   /* kway or recursive bisection */
1529fb83b9f2SMichael Gegg   real_t        *tpwgts;                    /* The fraction of vertex weights assigned to each partition */
1530fb83b9f2SMichael Gegg   real_t        *ubvec;                     /* The balance intolerance for vertex weights */
1531b3ce585bSLisandro Dalcin   PetscInt       options[64];               /* Options */
153270034214SMatthew G. Knepley   /* Outputs */
1533b3ce585bSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
1534b3ce585bSLisandro Dalcin   PetscMPIInt    size, rank, p;
153542678178SLisandro Dalcin   PetscInt       pm_randomSeed = -1;
153670034214SMatthew G. Knepley   PetscErrorCode ierr;
153770034214SMatthew G. Knepley 
153870034214SMatthew G. Knepley   PetscFunctionBegin;
153942678178SLisandro Dalcin   ierr = PetscOptionsGetInt(((PetscObject)part)->options,((PetscObject)part)->prefix,"-petscpartitioner_parmetis_seed", &pm_randomSeed, NULL);CHKERRQ(ierr);
154077623264SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr);
1541b3ce585bSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
154270034214SMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
154370034214SMatthew G. Knepley   /* Calculate vertex distribution */
1544b3ce585bSLisandro Dalcin   ierr = PetscMalloc5(size+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment,nvtxs,&vwgt);CHKERRQ(ierr);
154570034214SMatthew G. Knepley   vtxdist[0] = 0;
154670034214SMatthew G. Knepley   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
1547b3ce585bSLisandro Dalcin   for (p = 2; p <= size; ++p) {
154870034214SMatthew G. Knepley     vtxdist[p] += vtxdist[p-1];
154970034214SMatthew G. Knepley   }
155044d8be81SLisandro Dalcin   /* Calculate partition weights */
155170034214SMatthew G. Knepley   for (p = 0; p < nparts; ++p) {
155270034214SMatthew G. Knepley     tpwgts[p] = 1.0/nparts;
155370034214SMatthew G. Knepley   }
15545b440754SMatthew G. Knepley   ubvec[0] = pm->imbalanceRatio;
1555deea36a5SMatthew G. Knepley   /* Weight cells by dofs on cell by default */
1556e87a4003SBarry Smith   ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
1557deea36a5SMatthew G. Knepley   if (section) {
1558deea36a5SMatthew G. Knepley     PetscInt cStart, cEnd, dof;
155970034214SMatthew G. Knepley 
1560deea36a5SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
1561deea36a5SMatthew G. Knepley     for (v = cStart; v < cEnd; ++v) {
1562deea36a5SMatthew G. Knepley       ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
1563925b1076SLisandro Dalcin       /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
1564925b1076SLisandro Dalcin       /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
1565925b1076SLisandro Dalcin       if (v-cStart < numVertices) vwgt[v-cStart] = PetscMax(dof, 1);
1566deea36a5SMatthew G. Knepley     }
1567deea36a5SMatthew G. Knepley   } else {
1568deea36a5SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) vwgt[v] = 1;
1569cd0de0f2SShri   }
157044d8be81SLisandro Dalcin   wgtflag |= 2; /* have weights on graph vertices */
1571cd0de0f2SShri 
157270034214SMatthew G. Knepley   if (nparts == 1) {
15739fc93327SToby Isaac     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));CHKERRQ(ierr);
157470034214SMatthew G. Knepley   } else {
1575b3ce585bSLisandro Dalcin     for (p = 0; !vtxdist[p+1] && p < size; ++p);
1576b3ce585bSLisandro Dalcin     if (vtxdist[p+1] == vtxdist[size]) {
1577b3ce585bSLisandro Dalcin       if (rank == p) {
157844d8be81SLisandro Dalcin         ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
157942678178SLisandro Dalcin         options[METIS_OPTION_DBGLVL] = pm->debugFlag;
158042678178SLisandro Dalcin         options[METIS_OPTION_SEED]   = pm_randomSeed;
158144d8be81SLisandro Dalcin         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
158244d8be81SLisandro Dalcin         if (metis_ptype == 1) {
158344d8be81SLisandro Dalcin           PetscStackPush("METIS_PartGraphRecursive");
158472379da4SMatthew G. Knepley           ierr = METIS_PartGraphRecursive(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
158544d8be81SLisandro Dalcin           PetscStackPop;
158644d8be81SLisandro Dalcin           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphRecursive()");
158744d8be81SLisandro Dalcin         } else {
158844d8be81SLisandro Dalcin           /*
158944d8be81SLisandro Dalcin            It would be nice to activate the two options below, but they would need some actual testing.
159044d8be81SLisandro Dalcin            - Turning on these options may exercise path of the METIS code that have bugs and may break production runs.
159144d8be81SLisandro 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.
159244d8be81SLisandro Dalcin           */
159344d8be81SLisandro Dalcin           /* options[METIS_OPTION_CONTIG]  = 1; */ /* try to produce partitions that are contiguous */
159444d8be81SLisandro Dalcin           /* options[METIS_OPTION_MINCONN] = 1; */ /* minimize the maximum degree of the subdomain graph */
159570034214SMatthew G. Knepley           PetscStackPush("METIS_PartGraphKway");
159672379da4SMatthew G. Knepley           ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
159770034214SMatthew G. Knepley           PetscStackPop;
159870034214SMatthew G. Knepley           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
159970034214SMatthew G. Knepley         }
160044d8be81SLisandro Dalcin       }
160170034214SMatthew G. Knepley     } else {
160242678178SLisandro Dalcin       options[0] = 1; /*use options */
16035b440754SMatthew G. Knepley       options[1] = pm->debugFlag;
160442678178SLisandro Dalcin       options[2] = (pm_randomSeed == -1) ? 15 : pm_randomSeed; /* default is GLOBAL_SEED=15 from `libparmetis/defs.h` */
160570034214SMatthew G. Knepley       PetscStackPush("ParMETIS_V3_PartKway");
160672379da4SMatthew G. Knepley       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment, &comm);
160770034214SMatthew G. Knepley       PetscStackPop;
1608c717d290SMatthew G. Knepley       if (ierr != METIS_OK) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error %d in ParMETIS_V3_PartKway()", ierr);
160970034214SMatthew G. Knepley     }
161070034214SMatthew G. Knepley   }
161170034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
161277623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
161377623264SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
161477623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
161570034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
161677623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
161770034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
161870034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
161970034214SMatthew G. Knepley     }
162070034214SMatthew G. Knepley   }
162170034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
162270034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
1623cd0de0f2SShri   ierr = PetscFree5(vtxdist,tpwgts,ubvec,assignment,vwgt);CHKERRQ(ierr);
16249b80ac48SMatthew G. Knepley   PetscFunctionReturn(0);
162570034214SMatthew G. Knepley #else
162677623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
162770034214SMatthew G. Knepley #endif
162870034214SMatthew G. Knepley }
162970034214SMatthew G. Knepley 
1630d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part)
163177623264SMatthew G. Knepley {
163277623264SMatthew G. Knepley   PetscFunctionBegin;
163377623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_ParMetis;
163444d8be81SLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_ParMetis;
163577623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_ParMetis;
163677623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_ParMetis;
163777623264SMatthew G. Knepley   PetscFunctionReturn(0);
163877623264SMatthew G. Knepley }
163977623264SMatthew G. Knepley 
164077623264SMatthew G. Knepley /*MC
164177623264SMatthew G. Knepley   PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMetis library
164277623264SMatthew G. Knepley 
164377623264SMatthew G. Knepley   Level: intermediate
164477623264SMatthew G. Knepley 
164577623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
164677623264SMatthew G. Knepley M*/
164777623264SMatthew G. Knepley 
164877623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part)
164977623264SMatthew G. Knepley {
165077623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p;
165177623264SMatthew G. Knepley   PetscErrorCode          ierr;
165277623264SMatthew G. Knepley 
165377623264SMatthew G. Knepley   PetscFunctionBegin;
165477623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
165577623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
165677623264SMatthew G. Knepley   part->data = p;
165777623264SMatthew G. Knepley 
16585b440754SMatthew G. Knepley   p->ptype          = 0;
16595b440754SMatthew G. Knepley   p->imbalanceRatio = 1.05;
16605b440754SMatthew G. Knepley   p->debugFlag      = 0;
16615b440754SMatthew G. Knepley 
166277623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr);
166377623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr);
166470034214SMatthew G. Knepley   PetscFunctionReturn(0);
166570034214SMatthew G. Knepley }
166670034214SMatthew G. Knepley 
1667137cd93aSLisandro Dalcin 
1668137cd93aSLisandro Dalcin PetscBool PTScotchPartitionercite = PETSC_FALSE;
1669137cd93aSLisandro Dalcin const char PTScotchPartitionerCitation[] =
1670137cd93aSLisandro Dalcin   "@article{PTSCOTCH,\n"
1671137cd93aSLisandro Dalcin   "  author  = {C. Chevalier and F. Pellegrini},\n"
1672137cd93aSLisandro Dalcin   "  title   = {{PT-SCOTCH}: a tool for efficient parallel graph ordering},\n"
1673137cd93aSLisandro Dalcin   "  journal = {Parallel Computing},\n"
1674137cd93aSLisandro Dalcin   "  volume  = {34},\n"
1675137cd93aSLisandro Dalcin   "  number  = {6},\n"
1676137cd93aSLisandro Dalcin   "  pages   = {318--331},\n"
1677137cd93aSLisandro Dalcin   "  year    = {2008},\n"
1678137cd93aSLisandro Dalcin   "  doi     = {https://doi.org/10.1016/j.parco.2007.12.001}\n"
1679137cd93aSLisandro Dalcin   "}\n";
1680137cd93aSLisandro Dalcin 
1681137cd93aSLisandro Dalcin typedef struct {
1682137cd93aSLisandro Dalcin   PetscInt  strategy;
1683137cd93aSLisandro Dalcin   PetscReal imbalance;
1684137cd93aSLisandro Dalcin } PetscPartitioner_PTScotch;
1685137cd93aSLisandro Dalcin 
1686137cd93aSLisandro Dalcin static const char *const
1687137cd93aSLisandro Dalcin PTScotchStrategyList[] = {
1688137cd93aSLisandro Dalcin   "DEFAULT",
1689137cd93aSLisandro Dalcin   "QUALITY",
1690137cd93aSLisandro Dalcin   "SPEED",
1691137cd93aSLisandro Dalcin   "BALANCE",
1692137cd93aSLisandro Dalcin   "SAFETY",
1693137cd93aSLisandro Dalcin   "SCALABILITY",
1694137cd93aSLisandro Dalcin   "RECURSIVE",
1695137cd93aSLisandro Dalcin   "REMAP"
1696137cd93aSLisandro Dalcin };
1697137cd93aSLisandro Dalcin 
1698137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
1699137cd93aSLisandro Dalcin 
1700137cd93aSLisandro Dalcin EXTERN_C_BEGIN
1701137cd93aSLisandro Dalcin #include <ptscotch.h>
1702137cd93aSLisandro Dalcin EXTERN_C_END
1703137cd93aSLisandro Dalcin 
1704137cd93aSLisandro Dalcin #define CHKERRPTSCOTCH(ierr) do { if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error calling PT-Scotch library"); } while(0)
1705137cd93aSLisandro Dalcin 
1706137cd93aSLisandro Dalcin static int PTScotch_Strategy(PetscInt strategy)
1707137cd93aSLisandro Dalcin {
1708137cd93aSLisandro Dalcin   switch (strategy) {
1709137cd93aSLisandro Dalcin   case  0: return SCOTCH_STRATDEFAULT;
1710137cd93aSLisandro Dalcin   case  1: return SCOTCH_STRATQUALITY;
1711137cd93aSLisandro Dalcin   case  2: return SCOTCH_STRATSPEED;
1712137cd93aSLisandro Dalcin   case  3: return SCOTCH_STRATBALANCE;
1713137cd93aSLisandro Dalcin   case  4: return SCOTCH_STRATSAFETY;
1714137cd93aSLisandro Dalcin   case  5: return SCOTCH_STRATSCALABILITY;
1715137cd93aSLisandro Dalcin   case  6: return SCOTCH_STRATRECURSIVE;
1716137cd93aSLisandro Dalcin   case  7: return SCOTCH_STRATREMAP;
1717137cd93aSLisandro Dalcin   default: return SCOTCH_STRATDEFAULT;
1718137cd93aSLisandro Dalcin   }
1719137cd93aSLisandro Dalcin }
1720137cd93aSLisandro Dalcin 
1721137cd93aSLisandro Dalcin 
1722137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_Seq(SCOTCH_Num strategy, double imbalance, SCOTCH_Num n, SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
1723137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[])
1724137cd93aSLisandro Dalcin {
1725137cd93aSLisandro Dalcin   SCOTCH_Graph   grafdat;
1726137cd93aSLisandro Dalcin   SCOTCH_Strat   stradat;
1727137cd93aSLisandro Dalcin   SCOTCH_Num     vertnbr = n;
1728137cd93aSLisandro Dalcin   SCOTCH_Num     edgenbr = xadj[n];
1729137cd93aSLisandro Dalcin   SCOTCH_Num*    velotab = vtxwgt;
1730137cd93aSLisandro Dalcin   SCOTCH_Num*    edlotab = adjwgt;
1731137cd93aSLisandro Dalcin   SCOTCH_Num     flagval = strategy;
1732137cd93aSLisandro Dalcin   double         kbalval = imbalance;
1733137cd93aSLisandro Dalcin   PetscErrorCode ierr;
1734137cd93aSLisandro Dalcin 
1735137cd93aSLisandro Dalcin   PetscFunctionBegin;
1736d99a0000SVaclav Hapla   {
1737d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
1738d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
1739d99a0000SVaclav Hapla     if (!flg) velotab = NULL;
1740d99a0000SVaclav Hapla   }
1741137cd93aSLisandro Dalcin   ierr = SCOTCH_graphInit(&grafdat);CHKERRPTSCOTCH(ierr);
1742137cd93aSLisandro Dalcin   ierr = SCOTCH_graphBuild(&grafdat, 0, vertnbr, xadj, xadj + 1, velotab, NULL, edgenbr, adjncy, edlotab);CHKERRPTSCOTCH(ierr);
1743137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
1744137cd93aSLisandro Dalcin   ierr = SCOTCH_stratGraphMapBuild(&stradat, flagval, nparts, kbalval);CHKERRPTSCOTCH(ierr);
1745137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
1746137cd93aSLisandro Dalcin   ierr = SCOTCH_graphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
1747137cd93aSLisandro Dalcin #endif
1748137cd93aSLisandro Dalcin   ierr = SCOTCH_graphPart(&grafdat, nparts, &stradat, part);CHKERRPTSCOTCH(ierr);
1749137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
1750137cd93aSLisandro Dalcin   SCOTCH_graphExit(&grafdat);
1751137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1752137cd93aSLisandro Dalcin }
1753137cd93aSLisandro Dalcin 
1754137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_MPI(SCOTCH_Num strategy, double imbalance, SCOTCH_Num vtxdist[], SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
1755137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[], MPI_Comm comm)
1756137cd93aSLisandro Dalcin {
1757137cd93aSLisandro Dalcin   PetscMPIInt     procglbnbr;
1758137cd93aSLisandro Dalcin   PetscMPIInt     proclocnum;
1759137cd93aSLisandro Dalcin   SCOTCH_Arch     archdat;
1760137cd93aSLisandro Dalcin   SCOTCH_Dgraph   grafdat;
1761137cd93aSLisandro Dalcin   SCOTCH_Dmapping mappdat;
1762137cd93aSLisandro Dalcin   SCOTCH_Strat    stradat;
1763137cd93aSLisandro Dalcin   SCOTCH_Num      vertlocnbr;
1764137cd93aSLisandro Dalcin   SCOTCH_Num      edgelocnbr;
1765137cd93aSLisandro Dalcin   SCOTCH_Num*     veloloctab = vtxwgt;
1766137cd93aSLisandro Dalcin   SCOTCH_Num*     edloloctab = adjwgt;
1767137cd93aSLisandro Dalcin   SCOTCH_Num      flagval = strategy;
1768137cd93aSLisandro Dalcin   double          kbalval = imbalance;
1769137cd93aSLisandro Dalcin   PetscErrorCode  ierr;
1770137cd93aSLisandro Dalcin 
1771137cd93aSLisandro Dalcin   PetscFunctionBegin;
1772d99a0000SVaclav Hapla   {
1773d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
1774d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
1775d99a0000SVaclav Hapla     if (!flg) veloloctab = NULL;
1776d99a0000SVaclav Hapla   }
1777137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &procglbnbr);CHKERRQ(ierr);
1778137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &proclocnum);CHKERRQ(ierr);
1779137cd93aSLisandro Dalcin   vertlocnbr = vtxdist[proclocnum + 1] - vtxdist[proclocnum];
1780137cd93aSLisandro Dalcin   edgelocnbr = xadj[vertlocnbr];
1781137cd93aSLisandro Dalcin 
1782137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphInit(&grafdat, comm);CHKERRPTSCOTCH(ierr);
1783137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphBuild(&grafdat, 0, vertlocnbr, vertlocnbr, xadj, xadj + 1, veloloctab, NULL, edgelocnbr, edgelocnbr, adjncy, NULL, edloloctab);CHKERRPTSCOTCH(ierr);
1784137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
1785137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
1786137cd93aSLisandro Dalcin #endif
1787137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
1788137cd93aSLisandro Dalcin   ierr = SCOTCH_stratDgraphMapBuild(&stradat, flagval, procglbnbr, nparts, kbalval);CHKERRQ(ierr);
1789137cd93aSLisandro Dalcin   ierr = SCOTCH_archInit(&archdat);CHKERRPTSCOTCH(ierr);
1790137cd93aSLisandro Dalcin   ierr = SCOTCH_archCmplt(&archdat, nparts);CHKERRPTSCOTCH(ierr);
1791137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapInit(&grafdat, &mappdat, &archdat, part);CHKERRPTSCOTCH(ierr);
1792137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapCompute(&grafdat, &mappdat, &stradat);CHKERRPTSCOTCH(ierr);
1793137cd93aSLisandro Dalcin   SCOTCH_dgraphMapExit(&grafdat, &mappdat);
1794137cd93aSLisandro Dalcin   SCOTCH_archExit(&archdat);
1795137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
1796137cd93aSLisandro Dalcin   SCOTCH_dgraphExit(&grafdat);
1797137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1798137cd93aSLisandro Dalcin }
1799137cd93aSLisandro Dalcin 
1800137cd93aSLisandro Dalcin #endif /* PETSC_HAVE_PTSCOTCH */
1801137cd93aSLisandro Dalcin 
1802137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerDestroy_PTScotch(PetscPartitioner part)
1803137cd93aSLisandro Dalcin {
1804137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
1805137cd93aSLisandro Dalcin   PetscErrorCode             ierr;
1806137cd93aSLisandro Dalcin 
1807137cd93aSLisandro Dalcin   PetscFunctionBegin;
1808137cd93aSLisandro Dalcin   ierr = PetscFree(p);CHKERRQ(ierr);
1809137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1810137cd93aSLisandro Dalcin }
1811137cd93aSLisandro Dalcin 
1812137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch_Ascii(PetscPartitioner part, PetscViewer viewer)
1813137cd93aSLisandro Dalcin {
1814137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
1815137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
1816137cd93aSLisandro Dalcin 
1817137cd93aSLisandro Dalcin   PetscFunctionBegin;
1818137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1819137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using partitioning strategy %s\n",PTScotchStrategyList[p->strategy]);CHKERRQ(ierr);
1820137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using load imbalance ratio %g\n",(double)p->imbalance);CHKERRQ(ierr);
1821137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1822137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1823137cd93aSLisandro Dalcin }
1824137cd93aSLisandro Dalcin 
1825137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch(PetscPartitioner part, PetscViewer viewer)
1826137cd93aSLisandro Dalcin {
1827137cd93aSLisandro Dalcin   PetscBool      iascii;
1828137cd93aSLisandro Dalcin   PetscErrorCode ierr;
1829137cd93aSLisandro Dalcin 
1830137cd93aSLisandro Dalcin   PetscFunctionBegin;
1831137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1832137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1833137cd93aSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1834137cd93aSLisandro Dalcin   if (iascii) {ierr = PetscPartitionerView_PTScotch_Ascii(part, viewer);CHKERRQ(ierr);}
1835137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1836137cd93aSLisandro Dalcin }
1837137cd93aSLisandro Dalcin 
1838137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_PTScotch(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
1839137cd93aSLisandro Dalcin {
1840137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
1841137cd93aSLisandro Dalcin   const char *const         *slist = PTScotchStrategyList;
1842137cd93aSLisandro Dalcin   PetscInt                  nlist = (PetscInt)(sizeof(PTScotchStrategyList)/sizeof(PTScotchStrategyList[0]));
1843137cd93aSLisandro Dalcin   PetscBool                 flag;
1844137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
1845137cd93aSLisandro Dalcin 
1846137cd93aSLisandro Dalcin   PetscFunctionBegin;
1847137cd93aSLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner PTScotch Options");CHKERRQ(ierr);
1848137cd93aSLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_ptscotch_strategy","Partitioning strategy","",slist,nlist,slist[p->strategy],&p->strategy,&flag);CHKERRQ(ierr);
1849137cd93aSLisandro Dalcin   ierr = PetscOptionsReal("-petscpartitioner_ptscotch_imbalance","Load imbalance ratio","",p->imbalance,&p->imbalance,&flag);CHKERRQ(ierr);
1850137cd93aSLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
1851137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1852137cd93aSLisandro Dalcin }
1853137cd93aSLisandro Dalcin 
1854137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerPartition_PTScotch(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1855137cd93aSLisandro Dalcin {
1856137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
1857137cd93aSLisandro Dalcin   MPI_Comm       comm       = PetscObjectComm((PetscObject)part);
1858137cd93aSLisandro Dalcin   PetscInt       nvtxs      = numVertices; /* The number of vertices in full graph */
1859137cd93aSLisandro Dalcin   PetscInt      *vtxdist;                  /* Distribution of vertices across processes */
1860137cd93aSLisandro Dalcin   PetscInt      *xadj       = start;       /* Start of edge list for each vertex */
1861137cd93aSLisandro Dalcin   PetscInt      *adjncy     = adjacency;   /* Edge lists for all vertices */
1862137cd93aSLisandro Dalcin   PetscInt      *vwgt       = NULL;        /* Vertex weights */
1863137cd93aSLisandro Dalcin   PetscInt      *adjwgt     = NULL;        /* Edge weights */
1864137cd93aSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
1865137cd93aSLisandro Dalcin   PetscMPIInt    size, rank, p;
1866137cd93aSLisandro Dalcin   PetscErrorCode ierr;
1867137cd93aSLisandro Dalcin 
1868137cd93aSLisandro Dalcin   PetscFunctionBegin;
1869137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
1870137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
187199b53901SStefano Zampini   ierr = PetscMalloc2(size+1,&vtxdist,PetscMax(nvtxs,1),&assignment);CHKERRQ(ierr);
1872137cd93aSLisandro Dalcin 
1873137cd93aSLisandro Dalcin   /* Calculate vertex distribution */
1874137cd93aSLisandro Dalcin   vtxdist[0] = 0;
1875137cd93aSLisandro Dalcin   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
1876137cd93aSLisandro Dalcin   for (p = 2; p <= size; ++p) {
1877137cd93aSLisandro Dalcin     vtxdist[p] += vtxdist[p-1];
1878137cd93aSLisandro Dalcin   }
1879137cd93aSLisandro Dalcin 
1880137cd93aSLisandro Dalcin   if (nparts == 1) {
1881137cd93aSLisandro Dalcin     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));CHKERRQ(ierr);
1882137cd93aSLisandro Dalcin   } else {
1883137cd93aSLisandro Dalcin     PetscSection section;
1884137cd93aSLisandro Dalcin     /* Weight cells by dofs on cell by default */
1885137cd93aSLisandro Dalcin     ierr = PetscMalloc1(PetscMax(nvtxs,1),&vwgt);CHKERRQ(ierr);
1886e87a4003SBarry Smith     ierr = DMGetSection(dm, &section);CHKERRQ(ierr);
1887137cd93aSLisandro Dalcin     if (section) {
1888137cd93aSLisandro Dalcin       PetscInt vStart, vEnd, dof;
1889137cd93aSLisandro Dalcin       ierr = DMPlexGetHeightStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
1890137cd93aSLisandro Dalcin       for (v = vStart; v < vEnd; ++v) {
1891137cd93aSLisandro Dalcin         ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
1892137cd93aSLisandro Dalcin         /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
1893137cd93aSLisandro Dalcin         /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
1894137cd93aSLisandro Dalcin         if (v-vStart < numVertices) vwgt[v-vStart] = PetscMax(dof, 1);
1895137cd93aSLisandro Dalcin       }
1896137cd93aSLisandro Dalcin     } else {
1897137cd93aSLisandro Dalcin       for (v = 0; v < nvtxs; ++v) vwgt[v] = 1;
1898137cd93aSLisandro Dalcin     }
1899137cd93aSLisandro Dalcin     {
1900137cd93aSLisandro Dalcin       PetscPartitioner_PTScotch *pts = (PetscPartitioner_PTScotch *) part->data;
1901137cd93aSLisandro Dalcin       int                       strat = PTScotch_Strategy(pts->strategy);
1902137cd93aSLisandro Dalcin       double                    imbal = (double)pts->imbalance;
1903137cd93aSLisandro Dalcin 
1904137cd93aSLisandro Dalcin       for (p = 0; !vtxdist[p+1] && p < size; ++p);
1905137cd93aSLisandro Dalcin       if (vtxdist[p+1] == vtxdist[size]) {
1906137cd93aSLisandro Dalcin         if (rank == p) {
1907137cd93aSLisandro Dalcin           ierr = PTScotch_PartGraph_Seq(strat, imbal, nvtxs, xadj, adjncy, vwgt, adjwgt, nparts, assignment);CHKERRQ(ierr);
1908137cd93aSLisandro Dalcin         }
1909137cd93aSLisandro Dalcin       } else {
1910137cd93aSLisandro Dalcin         ierr = PTScotch_PartGraph_MPI(strat, imbal, vtxdist, xadj, adjncy, vwgt, adjwgt, nparts, assignment, comm);CHKERRQ(ierr);
1911137cd93aSLisandro Dalcin       }
1912137cd93aSLisandro Dalcin     }
1913137cd93aSLisandro Dalcin     ierr = PetscFree(vwgt);CHKERRQ(ierr);
1914137cd93aSLisandro Dalcin   }
1915137cd93aSLisandro Dalcin 
1916137cd93aSLisandro Dalcin   /* Convert to PetscSection+IS */
1917137cd93aSLisandro Dalcin   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1918137cd93aSLisandro Dalcin   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
1919137cd93aSLisandro Dalcin   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1920137cd93aSLisandro Dalcin   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
1921137cd93aSLisandro Dalcin   for (p = 0, i = 0; p < nparts; ++p) {
1922137cd93aSLisandro Dalcin     for (v = 0; v < nvtxs; ++v) {
1923137cd93aSLisandro Dalcin       if (assignment[v] == p) points[i++] = v;
1924137cd93aSLisandro Dalcin     }
1925137cd93aSLisandro Dalcin   }
1926137cd93aSLisandro Dalcin   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
1927137cd93aSLisandro Dalcin   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
1928137cd93aSLisandro Dalcin 
1929137cd93aSLisandro Dalcin   ierr = PetscFree2(vtxdist,assignment);CHKERRQ(ierr);
1930137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1931137cd93aSLisandro Dalcin #else
1932137cd93aSLisandro Dalcin   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-ptscotch.");
1933137cd93aSLisandro Dalcin #endif
1934137cd93aSLisandro Dalcin }
1935137cd93aSLisandro Dalcin 
1936137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerInitialize_PTScotch(PetscPartitioner part)
1937137cd93aSLisandro Dalcin {
1938137cd93aSLisandro Dalcin   PetscFunctionBegin;
1939137cd93aSLisandro Dalcin   part->ops->view           = PetscPartitionerView_PTScotch;
1940137cd93aSLisandro Dalcin   part->ops->destroy        = PetscPartitionerDestroy_PTScotch;
1941137cd93aSLisandro Dalcin   part->ops->partition      = PetscPartitionerPartition_PTScotch;
1942137cd93aSLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_PTScotch;
1943137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1944137cd93aSLisandro Dalcin }
1945137cd93aSLisandro Dalcin 
1946137cd93aSLisandro Dalcin /*MC
1947137cd93aSLisandro Dalcin   PETSCPARTITIONERPTSCOTCH = "ptscotch" - A PetscPartitioner object using the PT-Scotch library
1948137cd93aSLisandro Dalcin 
1949137cd93aSLisandro Dalcin   Level: intermediate
1950137cd93aSLisandro Dalcin 
1951137cd93aSLisandro Dalcin .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1952137cd93aSLisandro Dalcin M*/
1953137cd93aSLisandro Dalcin 
1954137cd93aSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_PTScotch(PetscPartitioner part)
1955137cd93aSLisandro Dalcin {
1956137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p;
1957137cd93aSLisandro Dalcin   PetscErrorCode          ierr;
1958137cd93aSLisandro Dalcin 
1959137cd93aSLisandro Dalcin   PetscFunctionBegin;
1960137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1961137cd93aSLisandro Dalcin   ierr = PetscNewLog(part, &p);CHKERRQ(ierr);
1962137cd93aSLisandro Dalcin   part->data = p;
1963137cd93aSLisandro Dalcin 
1964137cd93aSLisandro Dalcin   p->strategy  = 0;
1965137cd93aSLisandro Dalcin   p->imbalance = 0.01;
1966137cd93aSLisandro Dalcin 
1967137cd93aSLisandro Dalcin   ierr = PetscPartitionerInitialize_PTScotch(part);CHKERRQ(ierr);
1968137cd93aSLisandro Dalcin   ierr = PetscCitationsRegister(PTScotchPartitionerCitation, &PTScotchPartitionercite);CHKERRQ(ierr);
1969137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1970137cd93aSLisandro Dalcin }
1971137cd93aSLisandro Dalcin 
1972137cd93aSLisandro Dalcin 
19735680f57bSMatthew G. Knepley /*@
19745680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
19755680f57bSMatthew G. Knepley 
19765680f57bSMatthew G. Knepley   Not collective
19775680f57bSMatthew G. Knepley 
19785680f57bSMatthew G. Knepley   Input Parameter:
19795680f57bSMatthew G. Knepley . dm - The DM
19805680f57bSMatthew G. Knepley 
19815680f57bSMatthew G. Knepley   Output Parameter:
19825680f57bSMatthew G. Knepley . part - The PetscPartitioner
19835680f57bSMatthew G. Knepley 
19845680f57bSMatthew G. Knepley   Level: developer
19855680f57bSMatthew G. Knepley 
198698599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
198798599a47SLawrence Mitchell 
198898599a47SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerCreate()
19895680f57bSMatthew G. Knepley @*/
19905680f57bSMatthew G. Knepley PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
19915680f57bSMatthew G. Knepley {
19925680f57bSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *) dm->data;
19935680f57bSMatthew G. Knepley 
19945680f57bSMatthew G. Knepley   PetscFunctionBegin;
19955680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
19965680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
19975680f57bSMatthew G. Knepley   *part = mesh->partitioner;
19985680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
19995680f57bSMatthew G. Knepley }
20005680f57bSMatthew G. Knepley 
200171bb2955SLawrence Mitchell /*@
200271bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
200371bb2955SLawrence Mitchell 
200471bb2955SLawrence Mitchell   logically collective on dm and part
200571bb2955SLawrence Mitchell 
200671bb2955SLawrence Mitchell   Input Parameters:
200771bb2955SLawrence Mitchell + dm - The DM
200871bb2955SLawrence Mitchell - part - The partitioner
200971bb2955SLawrence Mitchell 
201071bb2955SLawrence Mitchell   Level: developer
201171bb2955SLawrence Mitchell 
201271bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
201371bb2955SLawrence Mitchell 
201471bb2955SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate()
201571bb2955SLawrence Mitchell @*/
201671bb2955SLawrence Mitchell PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
201771bb2955SLawrence Mitchell {
201871bb2955SLawrence Mitchell   DM_Plex       *mesh = (DM_Plex *) dm->data;
201971bb2955SLawrence Mitchell   PetscErrorCode ierr;
202071bb2955SLawrence Mitchell 
202171bb2955SLawrence Mitchell   PetscFunctionBegin;
202271bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
202371bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
202471bb2955SLawrence Mitchell   ierr = PetscObjectReference((PetscObject)part);CHKERRQ(ierr);
202571bb2955SLawrence Mitchell   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
202671bb2955SLawrence Mitchell   mesh->partitioner = part;
202771bb2955SLawrence Mitchell   PetscFunctionReturn(0);
202871bb2955SLawrence Mitchell }
202971bb2955SLawrence Mitchell 
2030e8f14785SLisandro Dalcin static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
2031270bba0cSToby Isaac {
2032270bba0cSToby Isaac   PetscErrorCode ierr;
2033270bba0cSToby Isaac 
2034270bba0cSToby Isaac   PetscFunctionBegin;
20356a5a2ffdSToby Isaac   if (up) {
20366a5a2ffdSToby Isaac     PetscInt parent;
20376a5a2ffdSToby Isaac 
2038270bba0cSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
20396a5a2ffdSToby Isaac     if (parent != point) {
20406a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
20416a5a2ffdSToby Isaac 
2042270bba0cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2043270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
2044270bba0cSToby Isaac         PetscInt cpoint = closure[2*i];
2045270bba0cSToby Isaac 
2046e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
20471b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
2048270bba0cSToby Isaac       }
2049270bba0cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
20506a5a2ffdSToby Isaac     }
20516a5a2ffdSToby Isaac   }
20526a5a2ffdSToby Isaac   if (down) {
20536a5a2ffdSToby Isaac     PetscInt numChildren;
20546a5a2ffdSToby Isaac     const PetscInt *children;
20556a5a2ffdSToby Isaac 
20566a5a2ffdSToby Isaac     ierr = DMPlexGetTreeChildren(dm,point,&numChildren,&children);CHKERRQ(ierr);
20576a5a2ffdSToby Isaac     if (numChildren) {
20586a5a2ffdSToby Isaac       PetscInt i;
20596a5a2ffdSToby Isaac 
20606a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
20616a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
20626a5a2ffdSToby Isaac 
2063e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
20641b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
20656a5a2ffdSToby Isaac       }
20666a5a2ffdSToby Isaac     }
20676a5a2ffdSToby Isaac   }
2068270bba0cSToby Isaac   PetscFunctionReturn(0);
2069270bba0cSToby Isaac }
2070270bba0cSToby Isaac 
2071825f8a23SLisandro Dalcin PETSC_INTERN PetscErrorCode DMPlexPartitionLabelClosure_Private(DM,DMLabel,PetscInt,PetscInt,const PetscInt[],IS*);
2072825f8a23SLisandro Dalcin 
2073825f8a23SLisandro Dalcin PetscErrorCode DMPlexPartitionLabelClosure_Private(DM dm, DMLabel label, PetscInt rank, PetscInt numPoints, const PetscInt points[], IS *closureIS)
2074825f8a23SLisandro Dalcin {
2075825f8a23SLisandro Dalcin   DM_Plex        *mesh = (DM_Plex *)dm->data;
2076825f8a23SLisandro Dalcin   PetscBool      hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
2077825f8a23SLisandro Dalcin   PetscInt       *closure = NULL, closureSize, nelems, *elems, off = 0, p, c;
2078825f8a23SLisandro Dalcin   PetscHSetI     ht;
2079825f8a23SLisandro Dalcin   PetscErrorCode ierr;
2080825f8a23SLisandro Dalcin 
2081825f8a23SLisandro Dalcin   PetscFunctionBegin;
2082825f8a23SLisandro Dalcin   ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
2083825f8a23SLisandro Dalcin   ierr = PetscHSetIResize(ht, numPoints*16);CHKERRQ(ierr);
2084825f8a23SLisandro Dalcin   for (p = 0; p < numPoints; ++p) {
2085825f8a23SLisandro Dalcin     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2086825f8a23SLisandro Dalcin     for (c = 0; c < closureSize*2; c += 2) {
2087825f8a23SLisandro Dalcin       ierr = PetscHSetIAdd(ht, closure[c]);CHKERRQ(ierr);
2088825f8a23SLisandro Dalcin       if (hasTree) {ierr = DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE);CHKERRQ(ierr);}
2089825f8a23SLisandro Dalcin     }
2090825f8a23SLisandro Dalcin   }
2091825f8a23SLisandro Dalcin   if (closure) {ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure);CHKERRQ(ierr);}
2092825f8a23SLisandro Dalcin   ierr = PetscHSetIGetSize(ht, &nelems);CHKERRQ(ierr);
2093825f8a23SLisandro Dalcin   ierr = PetscMalloc1(nelems, &elems);CHKERRQ(ierr);
2094825f8a23SLisandro Dalcin   ierr = PetscHSetIGetElems(ht, &off, elems);CHKERRQ(ierr);
2095825f8a23SLisandro Dalcin   ierr = PetscHSetIDestroy(&ht);CHKERRQ(ierr);
2096825f8a23SLisandro Dalcin   ierr = PetscSortInt(nelems, elems);CHKERRQ(ierr);
2097825f8a23SLisandro Dalcin   ierr = ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS);CHKERRQ(ierr);
2098825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
2099825f8a23SLisandro Dalcin }
2100825f8a23SLisandro Dalcin 
21015abbe4feSMichael Lange /*@
21025abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
21035abbe4feSMichael Lange 
21045abbe4feSMichael Lange   Input Parameters:
21055abbe4feSMichael Lange + dm     - The DM
21065abbe4feSMichael Lange - label  - DMLabel assinging ranks to remote roots
21075abbe4feSMichael Lange 
21085abbe4feSMichael Lange   Level: developer
21095abbe4feSMichael Lange 
21105abbe4feSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
21115abbe4feSMichael Lange @*/
21125abbe4feSMichael Lange PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
21139ffc88e4SToby Isaac {
2114825f8a23SLisandro Dalcin   IS              rankIS,   pointIS, closureIS;
21155abbe4feSMichael Lange   const PetscInt *ranks,   *points;
2116825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
21179ffc88e4SToby Isaac   PetscErrorCode  ierr;
21189ffc88e4SToby Isaac 
21199ffc88e4SToby Isaac   PetscFunctionBegin;
21205abbe4feSMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
21215abbe4feSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
21225abbe4feSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
21235abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
21245abbe4feSMichael Lange     const PetscInt rank = ranks[r];
21255abbe4feSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
21265abbe4feSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
21275abbe4feSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
2128825f8a23SLisandro Dalcin     ierr = DMPlexPartitionLabelClosure_Private(dm, label, rank, numPoints, points, &closureIS);CHKERRQ(ierr);
21295abbe4feSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
21305abbe4feSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2131825f8a23SLisandro Dalcin     ierr = DMLabelSetStratumIS(label, rank, closureIS);CHKERRQ(ierr);
2132825f8a23SLisandro Dalcin     ierr = ISDestroy(&closureIS);CHKERRQ(ierr);
21339ffc88e4SToby Isaac   }
21345abbe4feSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
21355abbe4feSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
21369ffc88e4SToby Isaac   PetscFunctionReturn(0);
21379ffc88e4SToby Isaac }
21389ffc88e4SToby Isaac 
213924d039d7SMichael Lange /*@
214024d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
214124d039d7SMichael Lange 
214224d039d7SMichael Lange   Input Parameters:
214324d039d7SMichael Lange + dm     - The DM
214424d039d7SMichael Lange - label  - DMLabel assinging ranks to remote roots
214524d039d7SMichael Lange 
214624d039d7SMichael Lange   Level: developer
214724d039d7SMichael Lange 
214824d039d7SMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
214924d039d7SMichael Lange @*/
215024d039d7SMichael Lange PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
215170034214SMatthew G. Knepley {
215224d039d7SMichael Lange   IS              rankIS,   pointIS;
215324d039d7SMichael Lange   const PetscInt *ranks,   *points;
215424d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
215524d039d7SMichael Lange   PetscInt       *adj = NULL;
215670034214SMatthew G. Knepley   PetscErrorCode  ierr;
215770034214SMatthew G. Knepley 
215870034214SMatthew G. Knepley   PetscFunctionBegin;
215924d039d7SMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
216024d039d7SMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
216124d039d7SMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
216224d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
216324d039d7SMichael Lange     const PetscInt rank = ranks[r];
216470034214SMatthew G. Knepley 
216524d039d7SMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
216624d039d7SMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
216724d039d7SMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
216870034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
216924d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
217024d039d7SMichael Lange       ierr = DMPlexGetAdjacency(dm, points[p], &adjSize, &adj);CHKERRQ(ierr);
217124d039d7SMichael Lange       for (a = 0; a < adjSize; ++a) {ierr = DMLabelSetValue(label, adj[a], rank);CHKERRQ(ierr);}
217270034214SMatthew G. Knepley     }
217324d039d7SMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
217424d039d7SMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
217570034214SMatthew G. Knepley   }
217624d039d7SMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
217724d039d7SMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
217824d039d7SMichael Lange   ierr = PetscFree(adj);CHKERRQ(ierr);
217924d039d7SMichael Lange   PetscFunctionReturn(0);
218070034214SMatthew G. Knepley }
218170034214SMatthew G. Knepley 
2182be200f8dSMichael Lange /*@
2183be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
2184be200f8dSMichael Lange 
2185be200f8dSMichael Lange   Input Parameters:
2186be200f8dSMichael Lange + dm     - The DM
2187be200f8dSMichael Lange - label  - DMLabel assinging ranks to remote roots
2188be200f8dSMichael Lange 
2189be200f8dSMichael Lange   Level: developer
2190be200f8dSMichael Lange 
2191be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
2192be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
2193be200f8dSMichael Lange 
2194be200f8dSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
2195be200f8dSMichael Lange @*/
2196be200f8dSMichael Lange PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
2197be200f8dSMichael Lange {
2198be200f8dSMichael Lange   MPI_Comm        comm;
2199be200f8dSMichael Lange   PetscMPIInt     rank;
2200be200f8dSMichael Lange   PetscSF         sfPoint;
22015d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
2202be200f8dSMichael Lange   IS              rankIS, pointIS;
2203be200f8dSMichael Lange   const PetscInt *ranks;
2204be200f8dSMichael Lange   PetscInt        numRanks, r;
2205be200f8dSMichael Lange   PetscErrorCode  ierr;
2206be200f8dSMichael Lange 
2207be200f8dSMichael Lange   PetscFunctionBegin;
2208be200f8dSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
2209be200f8dSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2210be200f8dSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
22115d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
22125d04f6ebSMichael Lange   ierr = DMLabelGather(label, sfPoint, &lblLeaves);CHKERRQ(ierr);
22135d04f6ebSMichael Lange   ierr = DMLabelGetValueIS(lblLeaves, &rankIS);CHKERRQ(ierr);
22145d04f6ebSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
22155d04f6ebSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
22165d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
22175d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
22185d04f6ebSMichael Lange     if (remoteRank == rank) continue;
22195d04f6ebSMichael Lange     ierr = DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS);CHKERRQ(ierr);
22205d04f6ebSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
22215d04f6ebSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
22225d04f6ebSMichael Lange   }
22235d04f6ebSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
22245d04f6ebSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
22255d04f6ebSMichael Lange   ierr = DMLabelDestroy(&lblLeaves);CHKERRQ(ierr);
2226be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
2227be200f8dSMichael Lange   ierr = DMLabelDistribute(label, sfPoint, &lblRoots);CHKERRQ(ierr);
2228be200f8dSMichael Lange   ierr = DMLabelGetValueIS(lblRoots, &rankIS);CHKERRQ(ierr);
2229be200f8dSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
2230be200f8dSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
2231be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
2232be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
2233be200f8dSMichael Lange     if (remoteRank == rank) continue;
2234be200f8dSMichael Lange     ierr = DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS);CHKERRQ(ierr);
2235be200f8dSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
2236be200f8dSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2237be200f8dSMichael Lange   }
2238be200f8dSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
2239be200f8dSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
2240be200f8dSMichael Lange   ierr = DMLabelDestroy(&lblRoots);CHKERRQ(ierr);
2241be200f8dSMichael Lange   PetscFunctionReturn(0);
2242be200f8dSMichael Lange }
2243be200f8dSMichael Lange 
22441fd9873aSMichael Lange /*@
22451fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
22461fd9873aSMichael Lange 
22471fd9873aSMichael Lange   Input Parameters:
22481fd9873aSMichael Lange + dm        - The DM
22491fd9873aSMichael Lange . rootLabel - DMLabel assinging ranks to local roots
22501fd9873aSMichael Lange . processSF - A star forest mapping into the local index on each remote rank
22511fd9873aSMichael Lange 
22521fd9873aSMichael Lange   Output Parameter:
22531fd9873aSMichael Lange - leafLabel - DMLabel assinging ranks to remote roots
22541fd9873aSMichael Lange 
22551fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
22561fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
22571fd9873aSMichael Lange 
22581fd9873aSMichael Lange   Level: developer
22591fd9873aSMichael Lange 
22601fd9873aSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
22611fd9873aSMichael Lange @*/
22621fd9873aSMichael Lange PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
22631fd9873aSMichael Lange {
22641fd9873aSMichael Lange   MPI_Comm           comm;
2265874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
2266874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
22671fd9873aSMichael Lange   PetscSF            sfPoint;
2268874ddda9SLisandro Dalcin   PetscSection       rootSection;
22691fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
22701fd9873aSMichael Lange   const PetscSFNode *remote;
22711fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
22721fd9873aSMichael Lange   IS                 valueIS;
2273874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
22741fd9873aSMichael Lange   PetscErrorCode     ierr;
22751fd9873aSMichael Lange 
22761fd9873aSMichael Lange   PetscFunctionBegin;
22771fd9873aSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
22781fd9873aSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
22799852e123SBarry Smith   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
22801fd9873aSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
22811fd9873aSMichael Lange 
22821fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
22831fd9873aSMichael Lange   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
22849852e123SBarry Smith   ierr = PetscSectionSetChart(rootSection, 0, size);CHKERRQ(ierr);
22851fd9873aSMichael Lange   ierr = DMLabelGetValueIS(rootLabel, &valueIS);CHKERRQ(ierr);
22861fd9873aSMichael Lange   ierr = ISGetLocalSize(valueIS, &numNeighbors);CHKERRQ(ierr);
22871fd9873aSMichael Lange   ierr = ISGetIndices(valueIS, &neighbors);CHKERRQ(ierr);
22881fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
22891fd9873aSMichael Lange     ierr = DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints);CHKERRQ(ierr);
22901fd9873aSMichael Lange     ierr = PetscSectionAddDof(rootSection, neighbors[n], numPoints);CHKERRQ(ierr);
22911fd9873aSMichael Lange   }
22921fd9873aSMichael Lange   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
2293874ddda9SLisandro Dalcin   ierr = PetscSectionGetStorageSize(rootSection, &rootSize);CHKERRQ(ierr);
2294874ddda9SLisandro Dalcin   ierr = PetscMalloc1(rootSize, &rootPoints);CHKERRQ(ierr);
22951fd9873aSMichael Lange   ierr = PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote);CHKERRQ(ierr);
22961fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
22971fd9873aSMichael Lange     IS              pointIS;
22981fd9873aSMichael Lange     const PetscInt *points;
22991fd9873aSMichael Lange 
23001fd9873aSMichael Lange     ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
23011fd9873aSMichael Lange     ierr = DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS);CHKERRQ(ierr);
23021fd9873aSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
23031fd9873aSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
23041fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
2305f8987ae8SMichael Lange       if (local) {ierr = PetscFindInt(points[p], nleaves, local, &l);CHKERRQ(ierr);}
2306f8987ae8SMichael Lange       else       {l = -1;}
23071fd9873aSMichael Lange       if (l >= 0) {rootPoints[off+p] = remote[l];}
23081fd9873aSMichael Lange       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
23091fd9873aSMichael Lange     }
23101fd9873aSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
23111fd9873aSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
23121fd9873aSMichael Lange   }
2313874ddda9SLisandro Dalcin 
2314874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
2315874ddda9SLisandro Dalcin   if (!processSF) {
2316874ddda9SLisandro Dalcin     PetscInt64  counter = 0;
2317874ddda9SLisandro Dalcin     PetscBool   locOverflow = PETSC_FALSE;
2318874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
2319874ddda9SLisandro Dalcin 
2320874ddda9SLisandro Dalcin     ierr = PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls);CHKERRQ(ierr);
2321874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
2322874ddda9SLisandro Dalcin       ierr = PetscSectionGetDof(rootSection, neighbors[n], &dof);CHKERRQ(ierr);
2323874ddda9SLisandro Dalcin       ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
2324874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
2325874ddda9SLisandro Dalcin       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2326874ddda9SLisandro Dalcin       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2327874ddda9SLisandro Dalcin #endif
2328874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt) dof;
2329874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt) off;
2330874ddda9SLisandro Dalcin     }
2331874ddda9SLisandro Dalcin     ierr = MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm);CHKERRQ(ierr);
2332874ddda9SLisandro Dalcin     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
2333874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
2334874ddda9SLisandro Dalcin     ierr = MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm);CHKERRQ(ierr);
2335874ddda9SLisandro Dalcin     if (!mpiOverflow) {
2336874ddda9SLisandro Dalcin       leafSize = (PetscInt) counter;
2337874ddda9SLisandro Dalcin       ierr = PetscMalloc1(leafSize, &leafPoints);CHKERRQ(ierr);
2338874ddda9SLisandro Dalcin       ierr = MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm);CHKERRQ(ierr);
2339874ddda9SLisandro Dalcin     }
2340874ddda9SLisandro Dalcin     ierr = PetscFree4(scounts, sdispls, rcounts, rdispls);CHKERRQ(ierr);
2341874ddda9SLisandro Dalcin   }
2342874ddda9SLisandro Dalcin 
2343874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
2344874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
2345874ddda9SLisandro Dalcin     PetscSF      procSF;
2346874ddda9SLisandro Dalcin     PetscSFNode  *remote;
2347874ddda9SLisandro Dalcin     PetscSection leafSection;
2348874ddda9SLisandro Dalcin 
2349874ddda9SLisandro Dalcin     if (processSF) {
2350874ddda9SLisandro Dalcin       ierr = PetscObjectReference((PetscObject)processSF);CHKERRQ(ierr);
2351874ddda9SLisandro Dalcin       procSF = processSF;
2352874ddda9SLisandro Dalcin     } else {
2353874ddda9SLisandro Dalcin       ierr = PetscMalloc1(size, &remote);CHKERRQ(ierr);
2354874ddda9SLisandro Dalcin       for (r = 0; r < size; ++r) { remote[r].rank  = r; remote[r].index = rank; }
2355874ddda9SLisandro Dalcin       ierr = PetscSFCreate(comm, &procSF);CHKERRQ(ierr);
2356874ddda9SLisandro Dalcin       ierr = PetscSFSetGraph(procSF, size, size, NULL, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER);CHKERRQ(ierr);
2357874ddda9SLisandro Dalcin     }
2358874ddda9SLisandro Dalcin 
2359874ddda9SLisandro Dalcin     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection);CHKERRQ(ierr);
23601fd9873aSMichael Lange     ierr = DMPlexDistributeData(dm, processSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints);CHKERRQ(ierr);
2361874ddda9SLisandro Dalcin     ierr = PetscSectionGetStorageSize(leafSection, &leafSize);CHKERRQ(ierr);
2362874ddda9SLisandro Dalcin     ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
2363874ddda9SLisandro Dalcin     ierr = PetscSFDestroy(&procSF);CHKERRQ(ierr);
2364874ddda9SLisandro Dalcin   }
2365874ddda9SLisandro Dalcin 
2366874ddda9SLisandro Dalcin   for (p = 0; p < leafSize; p++) {
23671fd9873aSMichael Lange     ierr = DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank);CHKERRQ(ierr);
23681fd9873aSMichael Lange   }
2369874ddda9SLisandro Dalcin 
2370874ddda9SLisandro Dalcin   ierr = ISRestoreIndices(valueIS, &neighbors);CHKERRQ(ierr);
2371874ddda9SLisandro Dalcin   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
23721fd9873aSMichael Lange   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
2373874ddda9SLisandro Dalcin   ierr = PetscFree(rootPoints);CHKERRQ(ierr);
23741fd9873aSMichael Lange   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
23751fd9873aSMichael Lange   PetscFunctionReturn(0);
23761fd9873aSMichael Lange }
23771fd9873aSMichael Lange 
2378aa3148a8SMichael Lange /*@
2379aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
2380aa3148a8SMichael Lange 
2381aa3148a8SMichael Lange   Input Parameters:
2382aa3148a8SMichael Lange + dm    - The DM
2383aa3148a8SMichael Lange . label - DMLabel assinging ranks to remote roots
2384aa3148a8SMichael Lange 
2385aa3148a8SMichael Lange   Output Parameter:
2386aa3148a8SMichael Lange - sf    - The star forest communication context encapsulating the defined mapping
2387aa3148a8SMichael Lange 
2388aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
2389aa3148a8SMichael Lange 
2390aa3148a8SMichael Lange   Level: developer
2391aa3148a8SMichael Lange 
2392aa3148a8SMichael Lange .seealso: DMPlexDistribute(), DMPlexCreateOverlap
2393aa3148a8SMichael Lange @*/
2394aa3148a8SMichael Lange PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
2395aa3148a8SMichael Lange {
23969852e123SBarry Smith   PetscMPIInt     rank, size;
239743f7d02bSMichael Lange   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0;
2398aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
239943f7d02bSMichael Lange   IS              remoteRootIS;
240043f7d02bSMichael Lange   const PetscInt *remoteRoots;
2401aa3148a8SMichael Lange   PetscErrorCode ierr;
2402aa3148a8SMichael Lange 
2403aa3148a8SMichael Lange   PetscFunctionBegin;
240443f7d02bSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
24059852e123SBarry Smith   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr);
2406aa3148a8SMichael Lange 
24079852e123SBarry Smith   for (numRemote = 0, n = 0; n < size; ++n) {
2408aa3148a8SMichael Lange     ierr = DMLabelGetStratumSize(label, n, &numPoints);CHKERRQ(ierr);
2409aa3148a8SMichael Lange     numRemote += numPoints;
2410aa3148a8SMichael Lange   }
2411aa3148a8SMichael Lange   ierr = PetscMalloc1(numRemote, &remotePoints);CHKERRQ(ierr);
241243f7d02bSMichael Lange   /* Put owned points first */
241343f7d02bSMichael Lange   ierr = DMLabelGetStratumSize(label, rank, &numPoints);CHKERRQ(ierr);
241443f7d02bSMichael Lange   if (numPoints > 0) {
241543f7d02bSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &remoteRootIS);CHKERRQ(ierr);
241643f7d02bSMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
241743f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
241843f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
241943f7d02bSMichael Lange       remotePoints[idx].rank = rank;
242043f7d02bSMichael Lange       idx++;
242143f7d02bSMichael Lange     }
242243f7d02bSMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
242343f7d02bSMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
242443f7d02bSMichael Lange   }
242543f7d02bSMichael Lange   /* Now add remote points */
24269852e123SBarry Smith   for (n = 0; n < size; ++n) {
2427aa3148a8SMichael Lange     ierr = DMLabelGetStratumSize(label, n, &numPoints);CHKERRQ(ierr);
242843f7d02bSMichael Lange     if (numPoints <= 0 || n == rank) continue;
2429aa3148a8SMichael Lange     ierr = DMLabelGetStratumIS(label, n, &remoteRootIS);CHKERRQ(ierr);
2430aa3148a8SMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2431aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
2432aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
2433aa3148a8SMichael Lange       remotePoints[idx].rank = n;
2434aa3148a8SMichael Lange       idx++;
2435aa3148a8SMichael Lange     }
2436aa3148a8SMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2437aa3148a8SMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
2438aa3148a8SMichael Lange   }
2439aa3148a8SMichael Lange   ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), sf);CHKERRQ(ierr);
2440aa3148a8SMichael Lange   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2441aa3148a8SMichael Lange   ierr = PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
244270034214SMatthew G. Knepley   PetscFunctionReturn(0);
244370034214SMatthew G. Knepley }
2444