xref: /petsc/src/dm/impls/plex/plexpartition.c (revision 83c5d7880efc51278a8116947247c0c9d7cc1ddd)
1af0996ceSBarry Smith #include <petsc/private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2e8f14785SLisandro Dalcin #include <petsc/private/hashseti.h>
370034214SMatthew G. Knepley 
477623264SMatthew G. Knepley PetscClassId PETSCPARTITIONER_CLASSID = 0;
577623264SMatthew G. Knepley 
677623264SMatthew G. Knepley PetscFunctionList PetscPartitionerList              = NULL;
777623264SMatthew G. Knepley PetscBool         PetscPartitionerRegisterAllCalled = PETSC_FALSE;
877623264SMatthew G. Knepley 
977623264SMatthew G. Knepley PetscBool ChacoPartitionercite = PETSC_FALSE;
1077623264SMatthew G. Knepley const char ChacoPartitionerCitation[] = "@inproceedings{Chaco95,\n"
1177623264SMatthew G. Knepley                                "  author    = {Bruce Hendrickson and Robert Leland},\n"
1277623264SMatthew G. Knepley                                "  title     = {A multilevel algorithm for partitioning graphs},\n"
1377623264SMatthew G. Knepley                                "  booktitle = {Supercomputing '95: Proceedings of the 1995 ACM/IEEE Conference on Supercomputing (CDROM)},"
1477623264SMatthew G. Knepley                                "  isbn      = {0-89791-816-9},\n"
1577623264SMatthew G. Knepley                                "  pages     = {28},\n"
16a8d69d7bSBarry Smith                                "  doi       = {https://doi.acm.org/10.1145/224170.224228},\n"
1777623264SMatthew G. Knepley                                "  publisher = {ACM Press},\n"
1877623264SMatthew G. Knepley                                "  address   = {New York},\n"
1977623264SMatthew G. Knepley                                "  year      = {1995}\n}\n";
2077623264SMatthew G. Knepley 
2177623264SMatthew G. Knepley PetscBool ParMetisPartitionercite = PETSC_FALSE;
2277623264SMatthew G. Knepley const char ParMetisPartitionerCitation[] = "@article{KarypisKumar98,\n"
2377623264SMatthew G. Knepley                                "  author  = {George Karypis and Vipin Kumar},\n"
2477623264SMatthew G. Knepley                                "  title   = {A Parallel Algorithm for Multilevel Graph Partitioning and Sparse Matrix Ordering},\n"
2577623264SMatthew G. Knepley                                "  journal = {Journal of Parallel and Distributed Computing},\n"
2677623264SMatthew G. Knepley                                "  volume  = {48},\n"
2777623264SMatthew G. Knepley                                "  pages   = {71--85},\n"
2877623264SMatthew G. Knepley                                "  year    = {1998}\n}\n";
2977623264SMatthew G. Knepley 
300134a67bSLisandro Dalcin PETSC_STATIC_INLINE PetscInt DMPlex_GlobalID(PetscInt point) { return point >= 0 ? point : -(point+1); }
310134a67bSLisandro Dalcin 
32bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_Native(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
33532c4e7dSMichael Lange {
34ffbd6163SMatthew G. Knepley   PetscInt       dim, depth, p, pStart, pEnd, a, adjSize, idx, size;
35389e55d8SMichael Lange   PetscInt      *adj = NULL, *vOffsets = NULL, *graph = NULL;
368cfe4c1fSMichael Lange   IS             cellNumbering;
378cfe4c1fSMichael Lange   const PetscInt *cellNum;
38532c4e7dSMichael Lange   PetscBool      useCone, useClosure;
39532c4e7dSMichael Lange   PetscSection   section;
40532c4e7dSMichael Lange   PetscSegBuffer adjBuffer;
418cfe4c1fSMichael Lange   PetscSF        sfPoint;
428f4e72b9SMatthew G. Knepley   PetscInt       *adjCells = NULL, *remoteCells = NULL;
438f4e72b9SMatthew G. Knepley   const PetscInt *local;
448f4e72b9SMatthew G. Knepley   PetscInt       nroots, nleaves, l;
45532c4e7dSMichael Lange   PetscMPIInt    rank;
46532c4e7dSMichael Lange   PetscErrorCode ierr;
47532c4e7dSMichael Lange 
48532c4e7dSMichael Lange   PetscFunctionBegin;
49532c4e7dSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
50ffbd6163SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
51ffbd6163SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
52ffbd6163SMatthew G. Knepley   if (dim != depth) {
53ffbd6163SMatthew G. Knepley     /* We do not handle the uninterpolated case here */
54ffbd6163SMatthew G. Knepley     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
55ffbd6163SMatthew G. Knepley     /* DMPlexCreateNeighborCSR does not make a numbering */
56ffbd6163SMatthew G. Knepley     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
57ffbd6163SMatthew G. Knepley     /* Different behavior for empty graphs */
58ffbd6163SMatthew G. Knepley     if (!*numVertices) {
59ffbd6163SMatthew G. Knepley       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
60ffbd6163SMatthew G. Knepley       (*offsets)[0] = 0;
61ffbd6163SMatthew G. Knepley     }
62ffbd6163SMatthew G. Knepley     /* Broken in parallel */
63ffbd6163SMatthew G. Knepley     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
64ffbd6163SMatthew G. Knepley     PetscFunctionReturn(0);
65ffbd6163SMatthew G. Knepley   }
668cfe4c1fSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
670134a67bSLisandro Dalcin   ierr = DMPlexGetHeightStratum(dm, height, &pStart, &pEnd);CHKERRQ(ierr);
68532c4e7dSMichael Lange   /* Build adjacency graph via a section/segbuffer */
69532c4e7dSMichael Lange   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &section);CHKERRQ(ierr);
70532c4e7dSMichael Lange   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
71532c4e7dSMichael Lange   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer);CHKERRQ(ierr);
72532c4e7dSMichael Lange   /* Always use FVM adjacency to create partitioner graph */
73b0441da4SMatthew G. Knepley   ierr = DMGetBasicAdjacency(dm, &useCone, &useClosure);CHKERRQ(ierr);
74b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, PETSC_TRUE, PETSC_FALSE);CHKERRQ(ierr);
750134a67bSLisandro Dalcin   ierr = DMPlexCreateNumbering_Internal(dm, pStart, pEnd, 0, NULL, sfPoint, &cellNumbering);CHKERRQ(ierr);
763fa7752dSToby Isaac   if (globalNumbering) {
773fa7752dSToby Isaac     ierr = PetscObjectReference((PetscObject)cellNumbering);CHKERRQ(ierr);
783fa7752dSToby Isaac     *globalNumbering = cellNumbering;
793fa7752dSToby Isaac   }
808cfe4c1fSMichael Lange   ierr = ISGetIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
818f4e72b9SMatthew G. Knepley   /* For all boundary faces (including faces adjacent to a ghost cell), record the local cell in adjCells
828f4e72b9SMatthew G. Knepley      Broadcast adjCells to remoteCells (to get cells from roots) and Reduce adjCells to remoteCells (to get cells from leaves)
838f4e72b9SMatthew G. Knepley    */
840134a67bSLisandro Dalcin   ierr = PetscSFGetGraph(sfPoint, &nroots, &nleaves, &local, NULL);CHKERRQ(ierr);
858f4e72b9SMatthew G. Knepley   if (nroots >= 0) {
868f4e72b9SMatthew G. Knepley     PetscInt fStart, fEnd, f;
878f4e72b9SMatthew G. Knepley 
888f4e72b9SMatthew G. Knepley     ierr = PetscCalloc2(nroots, &adjCells, nroots, &remoteCells);CHKERRQ(ierr);
890134a67bSLisandro Dalcin     ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
908f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) adjCells[l] = -3;
918f4e72b9SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
928f4e72b9SMatthew G. Knepley       const PetscInt *support;
938f4e72b9SMatthew G. Knepley       PetscInt        supportSize;
948f4e72b9SMatthew G. Knepley 
958f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
968f4e72b9SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
970134a67bSLisandro Dalcin       if (supportSize == 1) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
988f4e72b9SMatthew G. Knepley       else if (supportSize == 2) {
998f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
1000134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[1]]);
1018f4e72b9SMatthew G. Knepley         ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
1020134a67bSLisandro Dalcin         if (p >= 0) adjCells[f] = DMPlex_GlobalID(cellNum[support[0]]);
1030134a67bSLisandro Dalcin       }
1040134a67bSLisandro Dalcin       /* Handle non-conforming meshes */
1050134a67bSLisandro Dalcin       if (supportSize > 2) {
1060134a67bSLisandro Dalcin         PetscInt        numChildren, i;
1070134a67bSLisandro Dalcin         const PetscInt *children;
1080134a67bSLisandro Dalcin 
1090134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, f, &numChildren, &children);CHKERRQ(ierr);
1100134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1110134a67bSLisandro Dalcin           const PetscInt child = children[i];
1120134a67bSLisandro Dalcin           if (fStart <= child && child < fEnd) {
1130134a67bSLisandro Dalcin             ierr = DMPlexGetSupport(dm, child, &support);CHKERRQ(ierr);
1140134a67bSLisandro Dalcin             ierr = DMPlexGetSupportSize(dm, child, &supportSize);CHKERRQ(ierr);
1150134a67bSLisandro Dalcin             if (supportSize == 1) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1160134a67bSLisandro Dalcin             else if (supportSize == 2) {
1170134a67bSLisandro Dalcin               ierr = PetscFindInt(support[0], nleaves, local, &p);CHKERRQ(ierr);
1180134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[1]]);
1190134a67bSLisandro Dalcin               ierr = PetscFindInt(support[1], nleaves, local, &p);CHKERRQ(ierr);
1200134a67bSLisandro Dalcin               if (p >= 0) adjCells[child] = DMPlex_GlobalID(cellNum[support[0]]);
1210134a67bSLisandro Dalcin             }
1220134a67bSLisandro Dalcin           }
1230134a67bSLisandro Dalcin         }
1248f4e72b9SMatthew G. Knepley       }
1258f4e72b9SMatthew G. Knepley     }
1268f4e72b9SMatthew G. Knepley     for (l = 0; l < nroots; ++l) remoteCells[l] = -1;
1278f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastBegin(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1288f4e72b9SMatthew G. Knepley     ierr = PetscSFBcastEnd(dm->sf, MPIU_INT, adjCells, remoteCells);CHKERRQ(ierr);
1298f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceBegin(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1308f4e72b9SMatthew G. Knepley     ierr = PetscSFReduceEnd(dm->sf, MPIU_INT, adjCells, remoteCells, MPI_MAX);CHKERRQ(ierr);
1318f4e72b9SMatthew G. Knepley   }
1328f4e72b9SMatthew G. Knepley   /* Combine local and global adjacencies */
1338cfe4c1fSMichael Lange   for (*numVertices = 0, p = pStart; p < pEnd; p++) {
1348cfe4c1fSMichael Lange     /* Skip non-owned cells in parallel (ParMetis expects no overlap) */
1358cfe4c1fSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
1368f4e72b9SMatthew G. Knepley     /* Add remote cells */
1378f4e72b9SMatthew G. Knepley     if (remoteCells) {
1380134a67bSLisandro Dalcin       const PetscInt gp = DMPlex_GlobalID(cellNum[p]);
1390134a67bSLisandro Dalcin       PetscInt       coneSize, numChildren, c, i;
1400134a67bSLisandro Dalcin       const PetscInt *cone, *children;
1410134a67bSLisandro Dalcin 
1428f4e72b9SMatthew G. Knepley       ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1438f4e72b9SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1448f4e72b9SMatthew G. Knepley       for (c = 0; c < coneSize; ++c) {
1450134a67bSLisandro Dalcin         const PetscInt point = cone[c];
1460134a67bSLisandro Dalcin         if (remoteCells[point] >= 0 && remoteCells[point] != gp) {
1478f4e72b9SMatthew G. Knepley           PetscInt *PETSC_RESTRICT pBuf;
1488f4e72b9SMatthew G. Knepley           ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1498f4e72b9SMatthew G. Knepley           ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1500134a67bSLisandro Dalcin           *pBuf = remoteCells[point];
1510134a67bSLisandro Dalcin         }
1520134a67bSLisandro Dalcin         /* Handle non-conforming meshes */
1530134a67bSLisandro Dalcin         ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
1540134a67bSLisandro Dalcin         for (i = 0; i < numChildren; ++i) {
1550134a67bSLisandro Dalcin           const PetscInt child = children[i];
1560134a67bSLisandro Dalcin           if (remoteCells[child] >= 0 && remoteCells[child] != gp) {
1570134a67bSLisandro Dalcin             PetscInt *PETSC_RESTRICT pBuf;
1580134a67bSLisandro Dalcin             ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
1590134a67bSLisandro Dalcin             ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1600134a67bSLisandro Dalcin             *pBuf = remoteCells[child];
1610134a67bSLisandro Dalcin           }
1628f4e72b9SMatthew G. Knepley         }
1638f4e72b9SMatthew G. Knepley       }
1648f4e72b9SMatthew G. Knepley     }
1658f4e72b9SMatthew G. Knepley     /* Add local cells */
166532c4e7dSMichael Lange     adjSize = PETSC_DETERMINE;
167532c4e7dSMichael Lange     ierr = DMPlexGetAdjacency(dm, p, &adjSize, &adj);CHKERRQ(ierr);
168532c4e7dSMichael Lange     for (a = 0; a < adjSize; ++a) {
169532c4e7dSMichael Lange       const PetscInt point = adj[a];
170532c4e7dSMichael Lange       if (point != p && pStart <= point && point < pEnd) {
171532c4e7dSMichael Lange         PetscInt *PETSC_RESTRICT pBuf;
172532c4e7dSMichael Lange         ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr);
173532c4e7dSMichael Lange         ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr);
1740134a67bSLisandro Dalcin         *pBuf = DMPlex_GlobalID(cellNum[point]);
175532c4e7dSMichael Lange       }
176532c4e7dSMichael Lange     }
1778cfe4c1fSMichael Lange     (*numVertices)++;
178532c4e7dSMichael Lange   }
1794e468a93SLisandro Dalcin   ierr = PetscFree(adj);CHKERRQ(ierr);
1808f4e72b9SMatthew G. Knepley   ierr = PetscFree2(adjCells, remoteCells);CHKERRQ(ierr);
181b0441da4SMatthew G. Knepley   ierr = DMSetBasicAdjacency(dm, useCone, useClosure);CHKERRQ(ierr);
1824e468a93SLisandro Dalcin 
183532c4e7dSMichael Lange   /* Derive CSR graph from section/segbuffer */
184532c4e7dSMichael Lange   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
185532c4e7dSMichael Lange   ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
186389e55d8SMichael Lange   ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
18743f7d02bSMichael Lange   for (idx = 0, p = pStart; p < pEnd; p++) {
18843f7d02bSMichael Lange     if (nroots > 0) {if (cellNum[p] < 0) continue;}
18943f7d02bSMichael Lange     ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
19043f7d02bSMichael Lange   }
191532c4e7dSMichael Lange   vOffsets[*numVertices] = size;
192389e55d8SMichael Lange   ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
1934e468a93SLisandro Dalcin 
1944e468a93SLisandro Dalcin   if (nroots >= 0) {
1954e468a93SLisandro Dalcin     /* Filter out duplicate edges using section/segbuffer */
1964e468a93SLisandro Dalcin     ierr = PetscSectionReset(section);CHKERRQ(ierr);
1974e468a93SLisandro Dalcin     ierr = PetscSectionSetChart(section, 0, *numVertices);CHKERRQ(ierr);
1984e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
1994e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
2004e468a93SLisandro Dalcin       PetscInt numEdges = end-start, *PETSC_RESTRICT edges;
2014e468a93SLisandro Dalcin       ierr = PetscSortRemoveDupsInt(&numEdges, &graph[start]);CHKERRQ(ierr);
2024e468a93SLisandro Dalcin       ierr = PetscSectionSetDof(section, p, numEdges);CHKERRQ(ierr);
2034e468a93SLisandro Dalcin       ierr = PetscSegBufferGetInts(adjBuffer, numEdges, &edges);CHKERRQ(ierr);
204580bdb30SBarry Smith       ierr = PetscArraycpy(edges, &graph[start], numEdges);CHKERRQ(ierr);
2054e468a93SLisandro Dalcin     }
2064e468a93SLisandro Dalcin     ierr = PetscFree(vOffsets);CHKERRQ(ierr);
2074e468a93SLisandro Dalcin     ierr = PetscFree(graph);CHKERRQ(ierr);
2084e468a93SLisandro Dalcin     /* Derive CSR graph from section/segbuffer */
2094e468a93SLisandro Dalcin     ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
2104e468a93SLisandro Dalcin     ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr);
2114e468a93SLisandro Dalcin     ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr);
2124e468a93SLisandro Dalcin     for (idx = 0, p = 0; p < *numVertices; p++) {
2134e468a93SLisandro Dalcin       ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr);
2144e468a93SLisandro Dalcin     }
2154e468a93SLisandro Dalcin     vOffsets[*numVertices] = size;
2164e468a93SLisandro Dalcin     ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr);
2174e468a93SLisandro Dalcin   } else {
2184e468a93SLisandro Dalcin     /* Sort adjacencies (not strictly necessary) */
2194e468a93SLisandro Dalcin     for (p = 0; p < *numVertices; p++) {
2204e468a93SLisandro Dalcin       PetscInt start = vOffsets[p], end = vOffsets[p+1];
2214e468a93SLisandro Dalcin       ierr = PetscSortInt(end-start, &graph[start]);CHKERRQ(ierr);
2224e468a93SLisandro Dalcin     }
2234e468a93SLisandro Dalcin   }
2244e468a93SLisandro Dalcin 
2254e468a93SLisandro Dalcin   if (offsets) *offsets = vOffsets;
226389e55d8SMichael Lange   if (adjacency) *adjacency = graph;
2274e468a93SLisandro Dalcin 
228532c4e7dSMichael Lange   /* Cleanup */
229532c4e7dSMichael Lange   ierr = PetscSegBufferDestroy(&adjBuffer);CHKERRQ(ierr);
230532c4e7dSMichael Lange   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
2314e468a93SLisandro Dalcin   ierr = ISRestoreIndices(cellNumbering, &cellNum);CHKERRQ(ierr);
2324e468a93SLisandro Dalcin   ierr = ISDestroy(&cellNumbering);CHKERRQ(ierr);
233532c4e7dSMichael Lange   PetscFunctionReturn(0);
234532c4e7dSMichael Lange }
235532c4e7dSMichael Lange 
236bbbc8e51SStefano Zampini static PetscErrorCode DMPlexCreatePartitionerGraph_ViaMat(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
237bbbc8e51SStefano Zampini {
238bbbc8e51SStefano Zampini   Mat            conn, CSR;
239bbbc8e51SStefano Zampini   IS             fis, cis, cis_own;
240bbbc8e51SStefano Zampini   PetscSF        sfPoint;
241bbbc8e51SStefano Zampini   const PetscInt *rows, *cols, *ii, *jj;
242bbbc8e51SStefano Zampini   PetscInt       *idxs,*idxs2;
243*83c5d788SMatthew G. Knepley   PetscInt       dim, depth, floc, cloc, i, M, N, c, lm, m, cStart, cEnd, fStart, fEnd;
244bbbc8e51SStefano Zampini   PetscMPIInt    rank;
245bbbc8e51SStefano Zampini   PetscBool      flg;
246bbbc8e51SStefano Zampini   PetscErrorCode ierr;
247bbbc8e51SStefano Zampini 
248bbbc8e51SStefano Zampini   PetscFunctionBegin;
249bbbc8e51SStefano Zampini   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
250bbbc8e51SStefano Zampini   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
251bbbc8e51SStefano Zampini   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
252bbbc8e51SStefano Zampini   if (dim != depth) {
253bbbc8e51SStefano Zampini     /* We do not handle the uninterpolated case here */
254bbbc8e51SStefano Zampini     ierr = DMPlexCreateNeighborCSR(dm, height, numVertices, offsets, adjacency);CHKERRQ(ierr);
255bbbc8e51SStefano Zampini     /* DMPlexCreateNeighborCSR does not make a numbering */
256bbbc8e51SStefano Zampini     if (globalNumbering) {ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, globalNumbering);CHKERRQ(ierr);}
257bbbc8e51SStefano Zampini     /* Different behavior for empty graphs */
258bbbc8e51SStefano Zampini     if (!*numVertices) {
259bbbc8e51SStefano Zampini       ierr = PetscMalloc1(1, offsets);CHKERRQ(ierr);
260bbbc8e51SStefano Zampini       (*offsets)[0] = 0;
261bbbc8e51SStefano Zampini     }
262bbbc8e51SStefano Zampini     /* Broken in parallel */
263bbbc8e51SStefano Zampini     if (rank && *numVertices) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Parallel partitioning of uninterpolated meshes not supported");
264bbbc8e51SStefano Zampini     PetscFunctionReturn(0);
265bbbc8e51SStefano Zampini   }
266bbbc8e51SStefano Zampini   /* Interpolated and parallel case */
267bbbc8e51SStefano Zampini 
268bbbc8e51SStefano Zampini   /* numbering */
269bbbc8e51SStefano Zampini   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
270bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height, &cStart, &cEnd);CHKERRQ(ierr);
271bbbc8e51SStefano Zampini   ierr = DMPlexGetHeightStratum(dm, height+1, &fStart, &fEnd);CHKERRQ(ierr);
272bbbc8e51SStefano Zampini   ierr = DMPlexCreateNumbering_Internal(dm, cStart, cEnd, 0, &N, sfPoint, &cis);CHKERRQ(ierr);
273bbbc8e51SStefano Zampini   ierr = DMPlexCreateNumbering_Internal(dm, fStart, fEnd, 0, &M, sfPoint, &fis);CHKERRQ(ierr);
274bbbc8e51SStefano Zampini   if (globalNumbering) {
275bbbc8e51SStefano Zampini     ierr = ISDuplicate(cis, globalNumbering);CHKERRQ(ierr);
276bbbc8e51SStefano Zampini   }
277bbbc8e51SStefano Zampini 
278bbbc8e51SStefano Zampini   /* get positive global ids and local sizes for facets and cells */
279bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(fis, &m);CHKERRQ(ierr);
280bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
281bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
282bbbc8e51SStefano Zampini   for (i = 0, floc = 0; i < m; i++) {
283bbbc8e51SStefano Zampini     const PetscInt p = rows[i];
284bbbc8e51SStefano Zampini 
285bbbc8e51SStefano Zampini     if (p < 0) {
286bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
287bbbc8e51SStefano Zampini     } else {
288bbbc8e51SStefano Zampini       idxs[i] = p;
289bbbc8e51SStefano Zampini       floc   += 1;
290bbbc8e51SStefano Zampini     }
291bbbc8e51SStefano Zampini   }
292bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
293bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
294bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PETSC_COMM_SELF, m, idxs, PETSC_OWN_POINTER, &fis);CHKERRQ(ierr);
295bbbc8e51SStefano Zampini 
296bbbc8e51SStefano Zampini   ierr = ISGetLocalSize(cis, &m);CHKERRQ(ierr);
297bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
298bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs);CHKERRQ(ierr);
299bbbc8e51SStefano Zampini   ierr = PetscMalloc1(m, &idxs2);CHKERRQ(ierr);
300bbbc8e51SStefano Zampini   for (i = 0, cloc = 0; i < m; i++) {
301bbbc8e51SStefano Zampini     const PetscInt p = cols[i];
302bbbc8e51SStefano Zampini 
303bbbc8e51SStefano Zampini     if (p < 0) {
304bbbc8e51SStefano Zampini       idxs[i] = -(p+1);
305bbbc8e51SStefano Zampini     } else {
306bbbc8e51SStefano Zampini       idxs[i]       = p;
307bbbc8e51SStefano Zampini       idxs2[cloc++] = p;
308bbbc8e51SStefano Zampini     }
309bbbc8e51SStefano Zampini   }
310bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
311bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
312bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), m, idxs, PETSC_OWN_POINTER, &cis);CHKERRQ(ierr);
313bbbc8e51SStefano Zampini   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cloc, idxs2, PETSC_OWN_POINTER, &cis_own);CHKERRQ(ierr);
314bbbc8e51SStefano Zampini 
315bbbc8e51SStefano Zampini   /* Create matrix to hold F-C connectivity (MatMatTranspose Mult not supported for MPIAIJ) */
316bbbc8e51SStefano Zampini   ierr = MatCreate(PetscObjectComm((PetscObject)dm), &conn);CHKERRQ(ierr);
317bbbc8e51SStefano Zampini   ierr = MatSetSizes(conn, floc, cloc, M, N);CHKERRQ(ierr);
318bbbc8e51SStefano Zampini   ierr = MatSetType(conn, MATMPIAIJ);CHKERRQ(ierr);
319*83c5d788SMatthew G. Knepley   ierr = DMPlexGetMaxSizes(dm, NULL, &lm);CHKERRQ(ierr);
320*83c5d788SMatthew G. Knepley   ierr = MPI_Allreduce(&lm, &m, 1, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject) dm));CHKERRQ(ierr);
321bbbc8e51SStefano Zampini   ierr = MatMPIAIJSetPreallocation(conn, m, NULL, m, NULL);CHKERRQ(ierr);
322bbbc8e51SStefano Zampini 
323bbbc8e51SStefano Zampini   /* Assemble matrix */
324bbbc8e51SStefano Zampini   ierr = ISGetIndices(fis, &rows);CHKERRQ(ierr);
325bbbc8e51SStefano Zampini   ierr = ISGetIndices(cis, &cols);CHKERRQ(ierr);
326bbbc8e51SStefano Zampini   for (c = cStart; c < cEnd; c++) {
327bbbc8e51SStefano Zampini     const PetscInt *cone;
328bbbc8e51SStefano Zampini     PetscInt        coneSize, row, col, f;
329bbbc8e51SStefano Zampini 
330bbbc8e51SStefano Zampini     col  = cols[c-cStart];
331bbbc8e51SStefano Zampini     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
332bbbc8e51SStefano Zampini     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
333bbbc8e51SStefano Zampini     for (f = 0; f < coneSize; f++) {
334bbbc8e51SStefano Zampini       const PetscScalar v = 1.0;
335bbbc8e51SStefano Zampini       const PetscInt *children;
336bbbc8e51SStefano Zampini       PetscInt        numChildren, ch;
337bbbc8e51SStefano Zampini 
338bbbc8e51SStefano Zampini       row  = rows[cone[f]-fStart];
339bbbc8e51SStefano Zampini       ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
340bbbc8e51SStefano Zampini 
341bbbc8e51SStefano Zampini       /* non-conforming meshes */
342bbbc8e51SStefano Zampini       ierr = DMPlexGetTreeChildren(dm, cone[f], &numChildren, &children);CHKERRQ(ierr);
343bbbc8e51SStefano Zampini       for (ch = 0; ch < numChildren; ch++) {
344bbbc8e51SStefano Zampini         const PetscInt child = children[ch];
345bbbc8e51SStefano Zampini 
346bbbc8e51SStefano Zampini         if (child < fStart || child >= fEnd) continue;
347bbbc8e51SStefano Zampini         row  = rows[child-fStart];
348bbbc8e51SStefano Zampini         ierr = MatSetValues(conn, 1, &row, 1, &col, &v, INSERT_VALUES);CHKERRQ(ierr);
349bbbc8e51SStefano Zampini       }
350bbbc8e51SStefano Zampini     }
351bbbc8e51SStefano Zampini   }
352bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(fis, &rows);CHKERRQ(ierr);
353bbbc8e51SStefano Zampini   ierr = ISRestoreIndices(cis, &cols);CHKERRQ(ierr);
354bbbc8e51SStefano Zampini   ierr = ISDestroy(&fis);CHKERRQ(ierr);
355bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis);CHKERRQ(ierr);
356bbbc8e51SStefano Zampini   ierr = MatAssemblyBegin(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
357bbbc8e51SStefano Zampini   ierr = MatAssemblyEnd(conn, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
358bbbc8e51SStefano Zampini 
359bbbc8e51SStefano Zampini   /* Get parallel CSR by doing conn^T * conn */
360bbbc8e51SStefano Zampini   ierr = MatTransposeMatMult(conn, conn, MAT_INITIAL_MATRIX, PETSC_DEFAULT, &CSR);CHKERRQ(ierr);
361bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
362bbbc8e51SStefano Zampini 
363bbbc8e51SStefano Zampini   /* extract local part of the CSR */
364bbbc8e51SStefano Zampini   ierr = MatMPIAIJGetLocalMat(CSR, MAT_INITIAL_MATRIX, &conn);CHKERRQ(ierr);
365bbbc8e51SStefano Zampini   ierr = MatDestroy(&CSR);CHKERRQ(ierr);
366bbbc8e51SStefano Zampini   ierr = MatGetRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
367bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
368bbbc8e51SStefano Zampini 
369bbbc8e51SStefano Zampini   /* get back requested output */
370bbbc8e51SStefano Zampini   if (numVertices) *numVertices = m;
371bbbc8e51SStefano Zampini   if (offsets) {
372bbbc8e51SStefano Zampini     ierr = PetscCalloc1(m+1, &idxs);CHKERRQ(ierr);
373bbbc8e51SStefano Zampini     for (i = 1; i < m+1; i++) idxs[i] = ii[i] - i; /* ParMetis does not like self-connectivity */
374bbbc8e51SStefano Zampini     *offsets = idxs;
375bbbc8e51SStefano Zampini   }
376bbbc8e51SStefano Zampini   if (adjacency) {
377bbbc8e51SStefano Zampini     ierr = PetscMalloc1(ii[m] - m, &idxs);CHKERRQ(ierr);
378bbbc8e51SStefano Zampini     ierr = ISGetIndices(cis_own, &rows);CHKERRQ(ierr);
379bbbc8e51SStefano Zampini     for (i = 0, c = 0; i < m; i++) {
380bbbc8e51SStefano Zampini       PetscInt j, g = rows[i];
381bbbc8e51SStefano Zampini 
382bbbc8e51SStefano Zampini       for (j = ii[i]; j < ii[i+1]; j++) {
383bbbc8e51SStefano Zampini         if (jj[j] == g) continue; /* again, self-connectivity */
384bbbc8e51SStefano Zampini         idxs[c++] = jj[j];
385bbbc8e51SStefano Zampini       }
386bbbc8e51SStefano Zampini     }
387bbbc8e51SStefano Zampini     if (c != ii[m] - m) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected %D != %D",c,ii[m]-m);
388bbbc8e51SStefano Zampini     ierr = ISRestoreIndices(cis_own, &rows);CHKERRQ(ierr);
389bbbc8e51SStefano Zampini     *adjacency = idxs;
390bbbc8e51SStefano Zampini   }
391bbbc8e51SStefano Zampini 
392bbbc8e51SStefano Zampini   /* cleanup */
393bbbc8e51SStefano Zampini   ierr = ISDestroy(&cis_own);CHKERRQ(ierr);
394bbbc8e51SStefano Zampini   ierr = MatRestoreRowIJ(conn, 0, PETSC_FALSE, PETSC_FALSE, &m, &ii, &jj, &flg);CHKERRQ(ierr);
395bbbc8e51SStefano Zampini   if (!flg) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "No IJ format");
396bbbc8e51SStefano Zampini   ierr = MatDestroy(&conn);CHKERRQ(ierr);
397bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
398bbbc8e51SStefano Zampini }
399bbbc8e51SStefano Zampini 
400bbbc8e51SStefano Zampini /*@C
401bbbc8e51SStefano Zampini   DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner
402bbbc8e51SStefano Zampini 
403bbbc8e51SStefano Zampini   Input Parameters:
404bbbc8e51SStefano Zampini + dm      - The mesh DM dm
405bbbc8e51SStefano Zampini - height  - Height of the strata from which to construct the graph
406bbbc8e51SStefano Zampini 
407bbbc8e51SStefano Zampini   Output Parameter:
408bbbc8e51SStefano Zampini + numVertices     - Number of vertices in the graph
409bbbc8e51SStefano Zampini . offsets         - Point offsets in the graph
410bbbc8e51SStefano Zampini . adjacency       - Point connectivity in the graph
411bbbc8e51SStefano Zampini - globalNumbering - A map from the local cell numbering to the global numbering used in "adjacency".  Negative indicates that the cell is a duplicate from another process.
412bbbc8e51SStefano Zampini 
413bbbc8e51SStefano Zampini   The user can control the definition of adjacency for the mesh using DMSetAdjacency(). They should choose the combination appropriate for the function
414bbbc8e51SStefano Zampini   representation on the mesh. If requested, globalNumbering needs to be destroyed by the caller; offsets and adjacency need to be freed with PetscFree().
415bbbc8e51SStefano Zampini 
416bbbc8e51SStefano Zampini   Level: developer
417bbbc8e51SStefano Zampini 
418bbbc8e51SStefano Zampini .seealso: PetscPartitionerGetType(), PetscPartitionerCreate(), DMSetAdjacency()
419bbbc8e51SStefano Zampini @*/
420bbbc8e51SStefano Zampini PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering)
421bbbc8e51SStefano Zampini {
422bbbc8e51SStefano Zampini   PetscErrorCode ierr;
423bbbc8e51SStefano Zampini   PetscBool      usemat = PETSC_FALSE;
424bbbc8e51SStefano Zampini 
425bbbc8e51SStefano Zampini   PetscFunctionBegin;
426bbbc8e51SStefano Zampini   ierr = PetscOptionsGetBool(((PetscObject) dm)->options,((PetscObject) dm)->prefix, "-dm_plex_csr_via_mat", &usemat, NULL);CHKERRQ(ierr);
427bbbc8e51SStefano Zampini   if (usemat) {
428bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_ViaMat(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
429bbbc8e51SStefano Zampini   } else {
430bbbc8e51SStefano Zampini     ierr = DMPlexCreatePartitionerGraph_Native(dm, height, numVertices, offsets, adjacency, globalNumbering);CHKERRQ(ierr);
431bbbc8e51SStefano Zampini   }
432bbbc8e51SStefano Zampini   PetscFunctionReturn(0);
433bbbc8e51SStefano Zampini }
434bbbc8e51SStefano Zampini 
435d5577e40SMatthew G. Knepley /*@C
436d5577e40SMatthew G. Knepley   DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format.
437d5577e40SMatthew G. Knepley 
438fe2efc57SMark   Collective on DM
439d5577e40SMatthew G. Knepley 
440d5577e40SMatthew G. Knepley   Input Arguments:
441d5577e40SMatthew G. Knepley + dm - The DMPlex
442d5577e40SMatthew G. Knepley - cellHeight - The height of mesh points to treat as cells (default should be 0)
443d5577e40SMatthew G. Knepley 
444d5577e40SMatthew G. Knepley   Output Arguments:
445d5577e40SMatthew G. Knepley + numVertices - The number of local vertices in the graph, or cells in the mesh.
446d5577e40SMatthew G. Knepley . offsets     - The offset to the adjacency list for each cell
447d5577e40SMatthew G. Knepley - adjacency   - The adjacency list for all cells
448d5577e40SMatthew G. Knepley 
449d5577e40SMatthew G. Knepley   Note: This is suitable for input to a mesh partitioner like ParMetis.
450d5577e40SMatthew G. Knepley 
451d5577e40SMatthew G. Knepley   Level: advanced
452d5577e40SMatthew G. Knepley 
453d5577e40SMatthew G. Knepley .seealso: DMPlexCreate()
454d5577e40SMatthew G. Knepley @*/
45570034214SMatthew G. Knepley PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
45670034214SMatthew G. Knepley {
45770034214SMatthew G. Knepley   const PetscInt maxFaceCases = 30;
45870034214SMatthew G. Knepley   PetscInt       numFaceCases = 0;
45970034214SMatthew G. Knepley   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
46070034214SMatthew G. Knepley   PetscInt      *off, *adj;
46170034214SMatthew G. Knepley   PetscInt      *neighborCells = NULL;
46270034214SMatthew G. Knepley   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
46370034214SMatthew G. Knepley   PetscErrorCode ierr;
46470034214SMatthew G. Knepley 
46570034214SMatthew G. Knepley   PetscFunctionBegin;
46670034214SMatthew G. Knepley   /* For parallel partitioning, I think you have to communicate supports */
467c73cfb54SMatthew G. Knepley   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
46870034214SMatthew G. Knepley   cellDim = dim - cellHeight;
46970034214SMatthew G. Knepley   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
47070034214SMatthew G. Knepley   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
47170034214SMatthew G. Knepley   if (cEnd - cStart == 0) {
47270034214SMatthew G. Knepley     if (numVertices) *numVertices = 0;
47370034214SMatthew G. Knepley     if (offsets)   *offsets   = NULL;
47470034214SMatthew G. Knepley     if (adjacency) *adjacency = NULL;
47570034214SMatthew G. Knepley     PetscFunctionReturn(0);
47670034214SMatthew G. Knepley   }
47770034214SMatthew G. Knepley   numCells  = cEnd - cStart;
47870034214SMatthew G. Knepley   faceDepth = depth - cellHeight;
47970034214SMatthew G. Knepley   if (dim == depth) {
48070034214SMatthew G. Knepley     PetscInt f, fStart, fEnd;
48170034214SMatthew G. Knepley 
48270034214SMatthew G. Knepley     ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
48370034214SMatthew G. Knepley     /* Count neighboring cells */
48470034214SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr);
48570034214SMatthew G. Knepley     for (f = fStart; f < fEnd; ++f) {
48670034214SMatthew G. Knepley       const PetscInt *support;
48770034214SMatthew G. Knepley       PetscInt        supportSize;
48870034214SMatthew G. Knepley       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
48970034214SMatthew G. Knepley       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
49070034214SMatthew G. Knepley       if (supportSize == 2) {
4919ffc88e4SToby Isaac         PetscInt numChildren;
4929ffc88e4SToby Isaac 
4939ffc88e4SToby Isaac         ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
4949ffc88e4SToby Isaac         if (!numChildren) {
49570034214SMatthew G. Knepley           ++off[support[0]-cStart+1];
49670034214SMatthew G. Knepley           ++off[support[1]-cStart+1];
49770034214SMatthew G. Knepley         }
49870034214SMatthew G. Knepley       }
4999ffc88e4SToby Isaac     }
50070034214SMatthew G. Knepley     /* Prefix sum */
50170034214SMatthew G. Knepley     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
50270034214SMatthew G. Knepley     if (adjacency) {
50370034214SMatthew G. Knepley       PetscInt *tmp;
50470034214SMatthew G. Knepley 
50570034214SMatthew G. Knepley       ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
506854ce69bSBarry Smith       ierr = PetscMalloc1(numCells+1, &tmp);CHKERRQ(ierr);
507580bdb30SBarry Smith       ierr = PetscArraycpy(tmp, off, numCells+1);CHKERRQ(ierr);
50870034214SMatthew G. Knepley       /* Get neighboring cells */
50970034214SMatthew G. Knepley       for (f = fStart; f < fEnd; ++f) {
51070034214SMatthew G. Knepley         const PetscInt *support;
51170034214SMatthew G. Knepley         PetscInt        supportSize;
51270034214SMatthew G. Knepley         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
51370034214SMatthew G. Knepley         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
51470034214SMatthew G. Knepley         if (supportSize == 2) {
5159ffc88e4SToby Isaac           PetscInt numChildren;
5169ffc88e4SToby Isaac 
5179ffc88e4SToby Isaac           ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
5189ffc88e4SToby Isaac           if (!numChildren) {
51970034214SMatthew G. Knepley             adj[tmp[support[0]-cStart]++] = support[1];
52070034214SMatthew G. Knepley             adj[tmp[support[1]-cStart]++] = support[0];
52170034214SMatthew G. Knepley           }
52270034214SMatthew G. Knepley         }
5239ffc88e4SToby Isaac       }
52470034214SMatthew G. Knepley #if defined(PETSC_USE_DEBUG)
52570034214SMatthew 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);
52670034214SMatthew G. Knepley #endif
52770034214SMatthew G. Knepley       ierr = PetscFree(tmp);CHKERRQ(ierr);
52870034214SMatthew G. Knepley     }
52970034214SMatthew G. Knepley     if (numVertices) *numVertices = numCells;
53070034214SMatthew G. Knepley     if (offsets)   *offsets   = off;
53170034214SMatthew G. Knepley     if (adjacency) *adjacency = adj;
53270034214SMatthew G. Knepley     PetscFunctionReturn(0);
53370034214SMatthew G. Knepley   }
53470034214SMatthew G. Knepley   /* Setup face recognition */
53570034214SMatthew G. Knepley   if (faceDepth == 1) {
53670034214SMatthew 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 */
53770034214SMatthew G. Knepley 
53870034214SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) {
53970034214SMatthew G. Knepley       PetscInt corners;
54070034214SMatthew G. Knepley 
54170034214SMatthew G. Knepley       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
54270034214SMatthew G. Knepley       if (!cornersSeen[corners]) {
54370034214SMatthew G. Knepley         PetscInt nFV;
54470034214SMatthew G. Knepley 
54570034214SMatthew G. Knepley         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
54670034214SMatthew G. Knepley         cornersSeen[corners] = 1;
54770034214SMatthew G. Knepley 
54870034214SMatthew G. Knepley         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
54970034214SMatthew G. Knepley 
55070034214SMatthew G. Knepley         numFaceVertices[numFaceCases++] = nFV;
55170034214SMatthew G. Knepley       }
55270034214SMatthew G. Knepley     }
55370034214SMatthew G. Knepley   }
55470034214SMatthew G. Knepley   ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
55570034214SMatthew G. Knepley   /* Count neighboring cells */
55670034214SMatthew G. Knepley   for (cell = cStart; cell < cEnd; ++cell) {
55770034214SMatthew G. Knepley     PetscInt numNeighbors = PETSC_DETERMINE, n;
55870034214SMatthew G. Knepley 
5598b0b4c70SToby Isaac     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
56070034214SMatthew G. Knepley     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
56170034214SMatthew G. Knepley     for (n = 0; n < numNeighbors; ++n) {
56270034214SMatthew G. Knepley       PetscInt        cellPair[2];
56370034214SMatthew G. Knepley       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
56470034214SMatthew G. Knepley       PetscInt        meetSize = 0;
56570034214SMatthew G. Knepley       const PetscInt *meet    = NULL;
56670034214SMatthew G. Knepley 
56770034214SMatthew G. Knepley       cellPair[0] = cell; cellPair[1] = neighborCells[n];
56870034214SMatthew G. Knepley       if (cellPair[0] == cellPair[1]) continue;
56970034214SMatthew G. Knepley       if (!found) {
57070034214SMatthew G. Knepley         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
57170034214SMatthew G. Knepley         if (meetSize) {
57270034214SMatthew G. Knepley           PetscInt f;
57370034214SMatthew G. Knepley 
57470034214SMatthew G. Knepley           for (f = 0; f < numFaceCases; ++f) {
57570034214SMatthew G. Knepley             if (numFaceVertices[f] == meetSize) {
57670034214SMatthew G. Knepley               found = PETSC_TRUE;
57770034214SMatthew G. Knepley               break;
57870034214SMatthew G. Knepley             }
57970034214SMatthew G. Knepley           }
58070034214SMatthew G. Knepley         }
58170034214SMatthew G. Knepley         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
58270034214SMatthew G. Knepley       }
58370034214SMatthew G. Knepley       if (found) ++off[cell-cStart+1];
58470034214SMatthew G. Knepley     }
58570034214SMatthew G. Knepley   }
58670034214SMatthew G. Knepley   /* Prefix sum */
58770034214SMatthew G. Knepley   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
58870034214SMatthew G. Knepley 
58970034214SMatthew G. Knepley   if (adjacency) {
59070034214SMatthew G. Knepley     ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
59170034214SMatthew G. Knepley     /* Get neighboring cells */
59270034214SMatthew G. Knepley     for (cell = cStart; cell < cEnd; ++cell) {
59370034214SMatthew G. Knepley       PetscInt numNeighbors = PETSC_DETERMINE, n;
59470034214SMatthew G. Knepley       PetscInt cellOffset   = 0;
59570034214SMatthew G. Knepley 
5968b0b4c70SToby Isaac       ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
59770034214SMatthew G. Knepley       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
59870034214SMatthew G. Knepley       for (n = 0; n < numNeighbors; ++n) {
59970034214SMatthew G. Knepley         PetscInt        cellPair[2];
60070034214SMatthew G. Knepley         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
60170034214SMatthew G. Knepley         PetscInt        meetSize = 0;
60270034214SMatthew G. Knepley         const PetscInt *meet    = NULL;
60370034214SMatthew G. Knepley 
60470034214SMatthew G. Knepley         cellPair[0] = cell; cellPair[1] = neighborCells[n];
60570034214SMatthew G. Knepley         if (cellPair[0] == cellPair[1]) continue;
60670034214SMatthew G. Knepley         if (!found) {
60770034214SMatthew G. Knepley           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
60870034214SMatthew G. Knepley           if (meetSize) {
60970034214SMatthew G. Knepley             PetscInt f;
61070034214SMatthew G. Knepley 
61170034214SMatthew G. Knepley             for (f = 0; f < numFaceCases; ++f) {
61270034214SMatthew G. Knepley               if (numFaceVertices[f] == meetSize) {
61370034214SMatthew G. Knepley                 found = PETSC_TRUE;
61470034214SMatthew G. Knepley                 break;
61570034214SMatthew G. Knepley               }
61670034214SMatthew G. Knepley             }
61770034214SMatthew G. Knepley           }
61870034214SMatthew G. Knepley           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
61970034214SMatthew G. Knepley         }
62070034214SMatthew G. Knepley         if (found) {
62170034214SMatthew G. Knepley           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
62270034214SMatthew G. Knepley           ++cellOffset;
62370034214SMatthew G. Knepley         }
62470034214SMatthew G. Knepley       }
62570034214SMatthew G. Knepley     }
62670034214SMatthew G. Knepley   }
62770034214SMatthew G. Knepley   ierr = PetscFree(neighborCells);CHKERRQ(ierr);
62870034214SMatthew G. Knepley   if (numVertices) *numVertices = numCells;
62970034214SMatthew G. Knepley   if (offsets)   *offsets   = off;
63070034214SMatthew G. Knepley   if (adjacency) *adjacency = adj;
63170034214SMatthew G. Knepley   PetscFunctionReturn(0);
63270034214SMatthew G. Knepley }
63370034214SMatthew G. Knepley 
63477623264SMatthew G. Knepley /*@C
63577623264SMatthew G. Knepley   PetscPartitionerRegister - Adds a new PetscPartitioner implementation
63677623264SMatthew G. Knepley 
63777623264SMatthew G. Knepley   Not Collective
63877623264SMatthew G. Knepley 
63977623264SMatthew G. Knepley   Input Parameters:
64077623264SMatthew G. Knepley + name        - The name of a new user-defined creation routine
64177623264SMatthew G. Knepley - create_func - The creation routine itself
64277623264SMatthew G. Knepley 
64377623264SMatthew G. Knepley   Notes:
64477623264SMatthew G. Knepley   PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners
64577623264SMatthew G. Knepley 
64677623264SMatthew G. Knepley   Sample usage:
64777623264SMatthew G. Knepley .vb
64877623264SMatthew G. Knepley     PetscPartitionerRegister("my_part", MyPetscPartitionerCreate);
64977623264SMatthew G. Knepley .ve
65077623264SMatthew G. Knepley 
65177623264SMatthew G. Knepley   Then, your PetscPartitioner type can be chosen with the procedural interface via
65277623264SMatthew G. Knepley .vb
65377623264SMatthew G. Knepley     PetscPartitionerCreate(MPI_Comm, PetscPartitioner *);
65477623264SMatthew G. Knepley     PetscPartitionerSetType(PetscPartitioner, "my_part");
65577623264SMatthew G. Knepley .ve
65677623264SMatthew G. Knepley    or at runtime via the option
65777623264SMatthew G. Knepley .vb
65877623264SMatthew G. Knepley     -petscpartitioner_type my_part
65977623264SMatthew G. Knepley .ve
66077623264SMatthew G. Knepley 
66177623264SMatthew G. Knepley   Level: advanced
66277623264SMatthew G. Knepley 
66377623264SMatthew G. Knepley .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy()
66477623264SMatthew G. Knepley 
66577623264SMatthew G. Knepley @*/
66677623264SMatthew G. Knepley PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner))
66777623264SMatthew G. Knepley {
66877623264SMatthew G. Knepley   PetscErrorCode ierr;
66977623264SMatthew G. Knepley 
67077623264SMatthew G. Knepley   PetscFunctionBegin;
67177623264SMatthew G. Knepley   ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr);
67277623264SMatthew G. Knepley   PetscFunctionReturn(0);
67377623264SMatthew G. Knepley }
67477623264SMatthew G. Knepley 
67577623264SMatthew G. Knepley /*@C
67677623264SMatthew G. Knepley   PetscPartitionerSetType - Builds a particular PetscPartitioner
67777623264SMatthew G. Knepley 
678fe2efc57SMark   Collective on PetscPartitioner
67977623264SMatthew G. Knepley 
68077623264SMatthew G. Knepley   Input Parameters:
68177623264SMatthew G. Knepley + part - The PetscPartitioner object
68277623264SMatthew G. Knepley - name - The kind of partitioner
68377623264SMatthew G. Knepley 
68477623264SMatthew G. Knepley   Options Database Key:
68577623264SMatthew G. Knepley . -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types
68677623264SMatthew G. Knepley 
68777623264SMatthew G. Knepley   Level: intermediate
68877623264SMatthew G. Knepley 
68977623264SMatthew G. Knepley .seealso: PetscPartitionerGetType(), PetscPartitionerCreate()
69077623264SMatthew G. Knepley @*/
69177623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name)
69277623264SMatthew G. Knepley {
69377623264SMatthew G. Knepley   PetscErrorCode (*r)(PetscPartitioner);
69477623264SMatthew G. Knepley   PetscBool      match;
69577623264SMatthew G. Knepley   PetscErrorCode ierr;
69677623264SMatthew G. Knepley 
69777623264SMatthew G. Knepley   PetscFunctionBegin;
69877623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
69977623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr);
70077623264SMatthew G. Knepley   if (match) PetscFunctionReturn(0);
70177623264SMatthew G. Knepley 
7020f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
70377623264SMatthew G. Knepley   ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr);
70477623264SMatthew G. Knepley   if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name);
70577623264SMatthew G. Knepley 
70677623264SMatthew G. Knepley   if (part->ops->destroy) {
70777623264SMatthew G. Knepley     ierr = (*part->ops->destroy)(part);CHKERRQ(ierr);
70877623264SMatthew G. Knepley   }
709074d466cSStefano Zampini   part->noGraph = PETSC_FALSE;
710d57f96a3SLisandro Dalcin   ierr = PetscMemzero(part->ops, sizeof(*part->ops));CHKERRQ(ierr);
71177623264SMatthew G. Knepley   ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr);
712d57f96a3SLisandro Dalcin   ierr = (*r)(part);CHKERRQ(ierr);
71377623264SMatthew G. Knepley   PetscFunctionReturn(0);
71477623264SMatthew G. Knepley }
71577623264SMatthew G. Knepley 
71677623264SMatthew G. Knepley /*@C
71777623264SMatthew G. Knepley   PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object.
71877623264SMatthew G. Knepley 
71977623264SMatthew G. Knepley   Not Collective
72077623264SMatthew G. Knepley 
72177623264SMatthew G. Knepley   Input Parameter:
72277623264SMatthew G. Knepley . part - The PetscPartitioner
72377623264SMatthew G. Knepley 
72477623264SMatthew G. Knepley   Output Parameter:
72577623264SMatthew G. Knepley . name - The PetscPartitioner type name
72677623264SMatthew G. Knepley 
72777623264SMatthew G. Knepley   Level: intermediate
72877623264SMatthew G. Knepley 
72977623264SMatthew G. Knepley .seealso: PetscPartitionerSetType(), PetscPartitionerCreate()
73077623264SMatthew G. Knepley @*/
73177623264SMatthew G. Knepley PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name)
73277623264SMatthew G. Knepley {
73377623264SMatthew G. Knepley   PetscErrorCode ierr;
73477623264SMatthew G. Knepley 
73577623264SMatthew G. Knepley   PetscFunctionBegin;
73677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
73777623264SMatthew G. Knepley   PetscValidPointer(name, 2);
7380f51fdf8SToby Isaac   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
73977623264SMatthew G. Knepley   *name = ((PetscObject) part)->type_name;
74077623264SMatthew G. Knepley   PetscFunctionReturn(0);
74177623264SMatthew G. Knepley }
74277623264SMatthew G. Knepley 
74377623264SMatthew G. Knepley /*@C
744fe2efc57SMark    PetscPartitionerViewFromOptions - View from Options
745fe2efc57SMark 
746fe2efc57SMark    Collective on PetscPartitioner
747fe2efc57SMark 
748fe2efc57SMark    Input Parameters:
749fe2efc57SMark +  A - the PetscPartitioner object
750fe2efc57SMark .  obj - Optional object
751fe2efc57SMark -  name - command line option
752fe2efc57SMark 
753fe2efc57SMark    Level: intermediate
754fe2efc57SMark .seealso:  PetscPartitionerView(), PetscObjectViewFromOptions()
755fe2efc57SMark @*/
756fe2efc57SMark PetscErrorCode PetscPartitionerViewFromOptions(PetscPartitioner A,PetscObject obj,const char name[])
757fe2efc57SMark {
758fe2efc57SMark   PetscErrorCode ierr;
759fe2efc57SMark 
760fe2efc57SMark   PetscFunctionBegin;
761fe2efc57SMark   PetscValidHeaderSpecific(A,PETSCPARTITIONER_CLASSID,1);
762fe2efc57SMark   ierr = PetscObjectViewFromOptions((PetscObject)A,obj,name);CHKERRQ(ierr);
763fe2efc57SMark   PetscFunctionReturn(0);
764fe2efc57SMark }
765fe2efc57SMark 
766fe2efc57SMark /*@C
76777623264SMatthew G. Knepley   PetscPartitionerView - Views a PetscPartitioner
76877623264SMatthew G. Knepley 
769fe2efc57SMark   Collective on PetscPartitioner
77077623264SMatthew G. Knepley 
77177623264SMatthew G. Knepley   Input Parameter:
77277623264SMatthew G. Knepley + part - the PetscPartitioner object to view
77377623264SMatthew G. Knepley - v    - the viewer
77477623264SMatthew G. Knepley 
77577623264SMatthew G. Knepley   Level: developer
77677623264SMatthew G. Knepley 
77777623264SMatthew G. Knepley .seealso: PetscPartitionerDestroy()
77877623264SMatthew G. Knepley @*/
77977623264SMatthew G. Knepley PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v)
78077623264SMatthew G. Knepley {
781ffc59708SMatthew G. Knepley   PetscMPIInt    size;
7822abdaa70SMatthew G. Knepley   PetscBool      isascii;
78377623264SMatthew G. Knepley   PetscErrorCode ierr;
78477623264SMatthew G. Knepley 
78577623264SMatthew G. Knepley   PetscFunctionBegin;
78677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
78777623264SMatthew G. Knepley   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);}
7882abdaa70SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
7892abdaa70SMatthew G. Knepley   if (isascii) {
7902abdaa70SMatthew G. Knepley     ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
791ffc59708SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "Graph Partitioner: %d MPI Process%s\n", size, size > 1 ? "es" : "");CHKERRQ(ierr);
7922abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "  type: %s\n", part->hdr.type_name);CHKERRQ(ierr);
7932abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(v);CHKERRQ(ierr);
7942abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "edge cut: %D\n", part->edgeCut);CHKERRQ(ierr);
7952abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(v, "balance:  %.2g\n", part->balance);CHKERRQ(ierr);
7962abdaa70SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(v);CHKERRQ(ierr);
7972abdaa70SMatthew G. Knepley   }
79877623264SMatthew G. Knepley   if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);}
79977623264SMatthew G. Knepley   PetscFunctionReturn(0);
80077623264SMatthew G. Knepley }
80177623264SMatthew G. Knepley 
802a0058e54SToby Isaac static PetscErrorCode PetscPartitionerGetDefaultType(const char *currentType, const char **defaultType)
803a0058e54SToby Isaac {
804a0058e54SToby Isaac   PetscFunctionBegin;
805a0058e54SToby Isaac   if (!currentType) {
80656bf5a81SLisandro Dalcin #if defined(PETSC_HAVE_PARMETIS)
807a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERPARMETIS;
808137cd93aSLisandro Dalcin #elif defined(PETSC_HAVE_PTSCOTCH)
809137cd93aSLisandro Dalcin     *defaultType = PETSCPARTITIONERPTSCOTCH;
81056bf5a81SLisandro Dalcin #elif defined(PETSC_HAVE_CHACO)
81156bf5a81SLisandro Dalcin     *defaultType = PETSCPARTITIONERCHACO;
812a0058e54SToby Isaac #else
813a0058e54SToby Isaac     *defaultType = PETSCPARTITIONERSIMPLE;
814a0058e54SToby Isaac #endif
815a0058e54SToby Isaac   } else {
816a0058e54SToby Isaac     *defaultType = currentType;
817a0058e54SToby Isaac   }
818a0058e54SToby Isaac   PetscFunctionReturn(0);
819a0058e54SToby Isaac }
820a0058e54SToby Isaac 
82177623264SMatthew G. Knepley /*@
82277623264SMatthew G. Knepley   PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database
82377623264SMatthew G. Knepley 
824fe2efc57SMark   Collective on PetscPartitioner
82577623264SMatthew G. Knepley 
82677623264SMatthew G. Knepley   Input Parameter:
82777623264SMatthew G. Knepley . part - the PetscPartitioner object to set options for
82877623264SMatthew G. Knepley 
82977623264SMatthew G. Knepley   Level: developer
83077623264SMatthew G. Knepley 
83177623264SMatthew G. Knepley .seealso: PetscPartitionerView()
83277623264SMatthew G. Knepley @*/
83377623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part)
83477623264SMatthew G. Knepley {
8356bb9daa8SLisandro Dalcin   const char    *defaultType;
8366bb9daa8SLisandro Dalcin   char           name[256];
8376bb9daa8SLisandro Dalcin   PetscBool      flg;
83877623264SMatthew G. Knepley   PetscErrorCode ierr;
83977623264SMatthew G. Knepley 
84077623264SMatthew G. Knepley   PetscFunctionBegin;
84177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
8426bb9daa8SLisandro Dalcin   ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);
8436bb9daa8SLisandro Dalcin   ierr = PetscPartitionerGetDefaultType(((PetscObject) part)->type_name,&defaultType);CHKERRQ(ierr);
84477623264SMatthew G. Knepley   ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr);
8456bb9daa8SLisandro Dalcin   ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, sizeof(name), &flg);CHKERRQ(ierr);
8466bb9daa8SLisandro Dalcin   if (flg) {
8476bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr);
8486bb9daa8SLisandro Dalcin   } else if (!((PetscObject) part)->type_name) {
8496bb9daa8SLisandro Dalcin     ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr);
8506bb9daa8SLisandro Dalcin   }
8516bb9daa8SLisandro Dalcin   if (part->ops->setfromoptions) {
8526bb9daa8SLisandro Dalcin     ierr = (*part->ops->setfromoptions)(PetscOptionsObject,part);CHKERRQ(ierr);
8536bb9daa8SLisandro Dalcin   }
854783e1fb6SStefano Zampini   ierr = PetscViewerDestroy(&part->viewerGraph);CHKERRQ(ierr);
8550358368aSMatthew G. Knepley   ierr = PetscOptionsGetViewer(((PetscObject) part)->comm, ((PetscObject) part)->options, ((PetscObject) part)->prefix, "-petscpartitioner_view_graph", &part->viewerGraph, &part->formatGraph, &part->viewGraph);CHKERRQ(ierr);
85677623264SMatthew G. Knepley   /* process any options handlers added with PetscObjectAddOptionsHandler() */
8570633abcbSJed Brown   ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) part);CHKERRQ(ierr);
85877623264SMatthew G. Knepley   ierr = PetscOptionsEnd();CHKERRQ(ierr);
85977623264SMatthew G. Knepley   PetscFunctionReturn(0);
86077623264SMatthew G. Knepley }
86177623264SMatthew G. Knepley 
86277623264SMatthew G. Knepley /*@C
86377623264SMatthew G. Knepley   PetscPartitionerSetUp - Construct data structures for the PetscPartitioner
86477623264SMatthew G. Knepley 
865fe2efc57SMark   Collective on PetscPartitioner
86677623264SMatthew G. Knepley 
86777623264SMatthew G. Knepley   Input Parameter:
86877623264SMatthew G. Knepley . part - the PetscPartitioner object to setup
86977623264SMatthew G. Knepley 
87077623264SMatthew G. Knepley   Level: developer
87177623264SMatthew G. Knepley 
87277623264SMatthew G. Knepley .seealso: PetscPartitionerView(), PetscPartitionerDestroy()
87377623264SMatthew G. Knepley @*/
87477623264SMatthew G. Knepley PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part)
87577623264SMatthew G. Knepley {
87677623264SMatthew G. Knepley   PetscErrorCode ierr;
87777623264SMatthew G. Knepley 
87877623264SMatthew G. Knepley   PetscFunctionBegin;
87977623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
88077623264SMatthew G. Knepley   if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);}
88177623264SMatthew G. Knepley   PetscFunctionReturn(0);
88277623264SMatthew G. Knepley }
88377623264SMatthew G. Knepley 
88477623264SMatthew G. Knepley /*@
88577623264SMatthew G. Knepley   PetscPartitionerDestroy - Destroys a PetscPartitioner object
88677623264SMatthew G. Knepley 
887fe2efc57SMark   Collective on PetscPartitioner
88877623264SMatthew G. Knepley 
88977623264SMatthew G. Knepley   Input Parameter:
89077623264SMatthew G. Knepley . part - the PetscPartitioner object to destroy
89177623264SMatthew G. Knepley 
89277623264SMatthew G. Knepley   Level: developer
89377623264SMatthew G. Knepley 
89477623264SMatthew G. Knepley .seealso: PetscPartitionerView()
89577623264SMatthew G. Knepley @*/
89677623264SMatthew G. Knepley PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part)
89777623264SMatthew G. Knepley {
89877623264SMatthew G. Knepley   PetscErrorCode ierr;
89977623264SMatthew G. Knepley 
90077623264SMatthew G. Knepley   PetscFunctionBegin;
90177623264SMatthew G. Knepley   if (!*part) PetscFunctionReturn(0);
90277623264SMatthew G. Knepley   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
90377623264SMatthew G. Knepley 
90477623264SMatthew G. Knepley   if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);}
90577623264SMatthew G. Knepley   ((PetscObject) (*part))->refct = 0;
90677623264SMatthew G. Knepley 
9070358368aSMatthew G. Knepley   ierr = PetscViewerDestroy(&(*part)->viewerGraph);CHKERRQ(ierr);
90877623264SMatthew G. Knepley   if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);}
90977623264SMatthew G. Knepley   ierr = PetscHeaderDestroy(part);CHKERRQ(ierr);
91077623264SMatthew G. Knepley   PetscFunctionReturn(0);
91177623264SMatthew G. Knepley }
91277623264SMatthew G. Knepley 
91377623264SMatthew G. Knepley /*@
91477623264SMatthew G. Knepley   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
91577623264SMatthew G. Knepley 
916d083f849SBarry Smith   Collective
91777623264SMatthew G. Knepley 
91877623264SMatthew G. Knepley   Input Parameter:
91977623264SMatthew G. Knepley . comm - The communicator for the PetscPartitioner object
92077623264SMatthew G. Knepley 
92177623264SMatthew G. Knepley   Output Parameter:
92277623264SMatthew G. Knepley . part - The PetscPartitioner object
92377623264SMatthew G. Knepley 
92477623264SMatthew G. Knepley   Level: beginner
92577623264SMatthew G. Knepley 
926dae52e14SToby Isaac .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL, PETSCPARTITIONERSIMPLE, PETSCPARTITIONERGATHER
92777623264SMatthew G. Knepley @*/
92877623264SMatthew G. Knepley PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
92977623264SMatthew G. Knepley {
93077623264SMatthew G. Knepley   PetscPartitioner p;
931a0058e54SToby Isaac   const char       *partitionerType = NULL;
93277623264SMatthew G. Knepley   PetscErrorCode   ierr;
93377623264SMatthew G. Knepley 
93477623264SMatthew G. Knepley   PetscFunctionBegin;
93577623264SMatthew G. Knepley   PetscValidPointer(part, 2);
93677623264SMatthew G. Knepley   *part = NULL;
93783cde681SMatthew G. Knepley   ierr = DMInitializePackage();CHKERRQ(ierr);
93877623264SMatthew G. Knepley 
93973107ff1SLisandro Dalcin   ierr = PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr);
940a0058e54SToby Isaac   ierr = PetscPartitionerGetDefaultType(NULL,&partitionerType);CHKERRQ(ierr);
941a0058e54SToby Isaac   ierr = PetscPartitionerSetType(p,partitionerType);CHKERRQ(ierr);
94277623264SMatthew G. Knepley 
94372379da4SMatthew G. Knepley   p->edgeCut = 0;
94472379da4SMatthew G. Knepley   p->balance = 0.0;
94572379da4SMatthew G. Knepley 
94677623264SMatthew G. Knepley   *part = p;
94777623264SMatthew G. Knepley   PetscFunctionReturn(0);
94877623264SMatthew G. Knepley }
94977623264SMatthew G. Knepley 
95077623264SMatthew G. Knepley /*@
95177623264SMatthew G. Knepley   PetscPartitionerPartition - Create a non-overlapping partition of the cells in the mesh
95277623264SMatthew G. Knepley 
953fe2efc57SMark   Collective on PetscPartitioner
95477623264SMatthew G. Knepley 
95577623264SMatthew G. Knepley   Input Parameters:
95677623264SMatthew G. Knepley + part    - The PetscPartitioner
957f8987ae8SMichael Lange - dm      - The mesh DM
95877623264SMatthew G. Knepley 
95977623264SMatthew G. Knepley   Output Parameters:
96077623264SMatthew G. Knepley + partSection     - The PetscSection giving the division of points by partition
961f8987ae8SMichael Lange - partition       - The list of points by partition
96277623264SMatthew G. Knepley 
9630358368aSMatthew G. Knepley   Options Database:
9640358368aSMatthew G. Knepley . -petscpartitioner_view_graph - View the graph we are partitioning
9650358368aSMatthew G. Knepley 
96677623264SMatthew G. Knepley   Note: Instead of cells, points at a given height can be partitioned by calling PetscPartitionerSetPointHeight()
96777623264SMatthew G. Knepley 
96877623264SMatthew G. Knepley   Level: developer
96977623264SMatthew G. Knepley 
97077623264SMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerSetPointHeight(), PetscPartitionerCreate()
9714b15ede2SMatthew G. Knepley @*/
972f8987ae8SMichael Lange PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, DM dm, PetscSection partSection, IS *partition)
97377623264SMatthew G. Knepley {
97477623264SMatthew G. Knepley   PetscMPIInt    size;
97577623264SMatthew G. Knepley   PetscErrorCode ierr;
97677623264SMatthew G. Knepley 
97777623264SMatthew G. Knepley   PetscFunctionBegin;
97877623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
97977623264SMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
98077623264SMatthew G. Knepley   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
98177623264SMatthew G. Knepley   PetscValidPointer(partition, 5);
98277623264SMatthew G. Knepley   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
98377623264SMatthew G. Knepley   if (size == 1) {
98477623264SMatthew G. Knepley     PetscInt *points;
98577623264SMatthew G. Knepley     PetscInt  cStart, cEnd, c;
98677623264SMatthew G. Knepley 
98777623264SMatthew G. Knepley     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
98877623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr);
98977623264SMatthew G. Knepley     ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr);
99077623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
99177623264SMatthew G. Knepley     ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr);
99277623264SMatthew G. Knepley     for (c = cStart; c < cEnd; ++c) points[c] = c;
99377623264SMatthew G. Knepley     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
99477623264SMatthew G. Knepley     PetscFunctionReturn(0);
99577623264SMatthew G. Knepley   }
99677623264SMatthew G. Knepley   if (part->height == 0) {
997074d466cSStefano Zampini     PetscInt numVertices = 0;
99877623264SMatthew G. Knepley     PetscInt *start     = NULL;
99977623264SMatthew G. Knepley     PetscInt *adjacency = NULL;
10003fa7752dSToby Isaac     IS       globalNumbering;
100177623264SMatthew G. Knepley 
1002074d466cSStefano Zampini     if (!part->noGraph || part->viewGraph) {
1003074d466cSStefano Zampini       ierr = DMPlexCreatePartitionerGraph(dm, part->height, &numVertices, &start, &adjacency, &globalNumbering);CHKERRQ(ierr);
100413911537SStefano Zampini     } else { /* only compute the number of owned local vertices */
1005074d466cSStefano Zampini       const PetscInt *idxs;
1006074d466cSStefano Zampini       PetscInt       p, pStart, pEnd;
1007074d466cSStefano Zampini 
1008074d466cSStefano Zampini       ierr = DMPlexGetHeightStratum(dm, part->height, &pStart, &pEnd);CHKERRQ(ierr);
1009074d466cSStefano Zampini       ierr = DMPlexCreateNumbering_Internal(dm, pStart, pEnd, 0, NULL, dm->sf, &globalNumbering);CHKERRQ(ierr);
1010074d466cSStefano Zampini       ierr = ISGetIndices(globalNumbering, &idxs);CHKERRQ(ierr);
1011074d466cSStefano Zampini       for (p = 0; p < pEnd - pStart; p++) numVertices += idxs[p] < 0 ? 0 : 1;
1012074d466cSStefano Zampini       ierr = ISRestoreIndices(globalNumbering, &idxs);CHKERRQ(ierr);
1013074d466cSStefano Zampini     }
10140358368aSMatthew G. Knepley     if (part->viewGraph) {
10150358368aSMatthew G. Knepley       PetscViewer viewer = part->viewerGraph;
10160358368aSMatthew G. Knepley       PetscBool   isascii;
10170358368aSMatthew G. Knepley       PetscInt    v, i;
10180358368aSMatthew G. Knepley       PetscMPIInt rank;
10190358368aSMatthew G. Knepley 
10200358368aSMatthew G. Knepley       ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) viewer), &rank);CHKERRQ(ierr);
10210358368aSMatthew G. Knepley       ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
10220358368aSMatthew G. Knepley       if (isascii) {
10230358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
10240358368aSMatthew G. Knepley         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %D\n", rank, numVertices);CHKERRQ(ierr);
10250358368aSMatthew G. Knepley         for (v = 0; v < numVertices; ++v) {
10260358368aSMatthew G. Knepley           const PetscInt s = start[v];
10270358368aSMatthew G. Knepley           const PetscInt e = start[v+1];
10280358368aSMatthew G. Knepley 
10290358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%d]  ", rank);CHKERRQ(ierr);
10300358368aSMatthew G. Knepley           for (i = s; i < e; ++i) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%D ", adjacency[i]);CHKERRQ(ierr);}
10310358368aSMatthew G. Knepley           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D-%D)\n", s, e);CHKERRQ(ierr);
10320358368aSMatthew G. Knepley         }
10330358368aSMatthew G. Knepley         ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
10340358368aSMatthew G. Knepley         ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
10350358368aSMatthew G. Knepley       }
10360358368aSMatthew G. Knepley     }
1037bbbc8e51SStefano Zampini     if (!part->ops->partition) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONGSTATE, "PetscPartitioner has no partitioning method");
103877623264SMatthew G. Knepley     ierr = (*part->ops->partition)(part, dm, size, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
103977623264SMatthew G. Knepley     ierr = PetscFree(start);CHKERRQ(ierr);
104077623264SMatthew G. Knepley     ierr = PetscFree(adjacency);CHKERRQ(ierr);
10413fa7752dSToby Isaac     if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */
10423fa7752dSToby Isaac       const PetscInt *globalNum;
10433fa7752dSToby Isaac       const PetscInt *partIdx;
10443fa7752dSToby Isaac       PetscInt       *map, cStart, cEnd;
10453fa7752dSToby Isaac       PetscInt       *adjusted, i, localSize, offset;
10463fa7752dSToby Isaac       IS             newPartition;
10473fa7752dSToby Isaac 
10483fa7752dSToby Isaac       ierr = ISGetLocalSize(*partition,&localSize);CHKERRQ(ierr);
10493fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&adjusted);CHKERRQ(ierr);
10503fa7752dSToby Isaac       ierr = ISGetIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
10513fa7752dSToby Isaac       ierr = ISGetIndices(*partition,&partIdx);CHKERRQ(ierr);
10523fa7752dSToby Isaac       ierr = PetscMalloc1(localSize,&map);CHKERRQ(ierr);
10533fa7752dSToby Isaac       ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
10543fa7752dSToby Isaac       for (i = cStart, offset = 0; i < cEnd; i++) {
10553fa7752dSToby Isaac         if (globalNum[i - cStart] >= 0) map[offset++] = i;
10563fa7752dSToby Isaac       }
10573fa7752dSToby Isaac       for (i = 0; i < localSize; i++) {
10583fa7752dSToby Isaac         adjusted[i] = map[partIdx[i]];
10593fa7752dSToby Isaac       }
10603fa7752dSToby Isaac       ierr = PetscFree(map);CHKERRQ(ierr);
10613fa7752dSToby Isaac       ierr = ISRestoreIndices(*partition,&partIdx);CHKERRQ(ierr);
10623fa7752dSToby Isaac       ierr = ISRestoreIndices(globalNumbering,&globalNum);CHKERRQ(ierr);
10633fa7752dSToby Isaac       ierr = ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition);CHKERRQ(ierr);
10643fa7752dSToby Isaac       ierr = ISDestroy(&globalNumbering);CHKERRQ(ierr);
10653fa7752dSToby Isaac       ierr = ISDestroy(partition);CHKERRQ(ierr);
10663fa7752dSToby Isaac       *partition = newPartition;
10673fa7752dSToby Isaac     }
106877623264SMatthew G. Knepley   } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
10692abdaa70SMatthew G. Knepley   ierr = PetscPartitionerViewFromOptions(part, NULL, "-petscpartitioner_view");CHKERRQ(ierr);
107077623264SMatthew G. Knepley   PetscFunctionReturn(0);
107177623264SMatthew G. Knepley }
107277623264SMatthew G. Knepley 
1073d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part)
107477623264SMatthew G. Knepley {
107577623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
107677623264SMatthew G. Knepley   PetscErrorCode          ierr;
107777623264SMatthew G. Knepley 
107877623264SMatthew G. Knepley   PetscFunctionBegin;
107977623264SMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
108077623264SMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
108177623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
108277623264SMatthew G. Knepley   PetscFunctionReturn(0);
108377623264SMatthew G. Knepley }
108477623264SMatthew G. Knepley 
1085d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer)
108677623264SMatthew G. Knepley {
1087077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
108877623264SMatthew G. Knepley   PetscErrorCode          ierr;
108977623264SMatthew G. Knepley 
109077623264SMatthew G. Knepley   PetscFunctionBegin;
1091077101c0SMatthew G. Knepley   if (p->random) {
1092077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1093077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPrintf(viewer, "using random partition\n");CHKERRQ(ierr);
1094077101c0SMatthew G. Knepley     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1095077101c0SMatthew G. Knepley   }
109677623264SMatthew G. Knepley   PetscFunctionReturn(0);
109777623264SMatthew G. Knepley }
109877623264SMatthew G. Knepley 
1099d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer)
110077623264SMatthew G. Knepley {
110177623264SMatthew G. Knepley   PetscBool      iascii;
110277623264SMatthew G. Knepley   PetscErrorCode ierr;
110377623264SMatthew G. Knepley 
110477623264SMatthew G. Knepley   PetscFunctionBegin;
110577623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
110677623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
110777623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
110877623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);}
110977623264SMatthew G. Knepley   PetscFunctionReturn(0);
111077623264SMatthew G. Knepley }
111177623264SMatthew G. Knepley 
1112d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerSetFromOptions_Shell(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
1113077101c0SMatthew G. Knepley {
1114077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1115077101c0SMatthew G. Knepley   PetscErrorCode          ierr;
1116077101c0SMatthew G. Knepley 
1117077101c0SMatthew G. Knepley   PetscFunctionBegin;
1118077101c0SMatthew G. Knepley   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner Shell Options");CHKERRQ(ierr);
1119077101c0SMatthew G. Knepley   ierr = PetscOptionsBool("-petscpartitioner_shell_random", "Use a random partition", "PetscPartitionerView", PETSC_FALSE, &p->random, NULL);CHKERRQ(ierr);
1120077101c0SMatthew G. Knepley   ierr = PetscOptionsTail();CHKERRQ(ierr);
1121077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1122077101c0SMatthew G. Knepley }
1123077101c0SMatthew G. Knepley 
1124d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
112577623264SMatthew G. Knepley {
112677623264SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
112777623264SMatthew G. Knepley   PetscInt                np;
112877623264SMatthew G. Knepley   PetscErrorCode          ierr;
112977623264SMatthew G. Knepley 
113077623264SMatthew G. Knepley   PetscFunctionBegin;
1131077101c0SMatthew G. Knepley   if (p->random) {
1132077101c0SMatthew G. Knepley     PetscRandom r;
1133aa1d5631SMatthew G. Knepley     PetscInt   *sizes, *points, v, p;
1134aa1d5631SMatthew G. Knepley     PetscMPIInt rank;
1135077101c0SMatthew G. Knepley 
1136aa1d5631SMatthew G. Knepley     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
1137077101c0SMatthew G. Knepley     ierr = PetscRandomCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr);
1138c717d290SMatthew G. Knepley     ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) nparts);CHKERRQ(ierr);
1139077101c0SMatthew G. Knepley     ierr = PetscRandomSetFromOptions(r);CHKERRQ(ierr);
1140077101c0SMatthew G. Knepley     ierr = PetscCalloc2(nparts, &sizes, numVertices, &points);CHKERRQ(ierr);
1141aa1d5631SMatthew G. Knepley     for (v = 0; v < numVertices; ++v) {points[v] = v;}
1142ac9a96f1SMichael Lange     for (p = 0; p < nparts; ++p) {sizes[p] = numVertices/nparts + (PetscInt) (p < numVertices % nparts);}
1143aa1d5631SMatthew G. Knepley     for (v = numVertices-1; v > 0; --v) {
1144077101c0SMatthew G. Knepley       PetscReal val;
1145aa1d5631SMatthew G. Knepley       PetscInt  w, tmp;
1146077101c0SMatthew G. Knepley 
1147aa1d5631SMatthew G. Knepley       ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) (v+1));CHKERRQ(ierr);
1148077101c0SMatthew G. Knepley       ierr = PetscRandomGetValueReal(r, &val);CHKERRQ(ierr);
1149aa1d5631SMatthew G. Knepley       w    = PetscFloorReal(val);
1150aa1d5631SMatthew G. Knepley       tmp       = points[v];
1151aa1d5631SMatthew G. Knepley       points[v] = points[w];
1152aa1d5631SMatthew G. Knepley       points[w] = tmp;
1153077101c0SMatthew G. Knepley     }
1154077101c0SMatthew G. Knepley     ierr = PetscRandomDestroy(&r);CHKERRQ(ierr);
1155077101c0SMatthew G. Knepley     ierr = PetscPartitionerShellSetPartition(part, nparts, sizes, points);CHKERRQ(ierr);
1156077101c0SMatthew G. Knepley     ierr = PetscFree2(sizes, points);CHKERRQ(ierr);
1157077101c0SMatthew G. Knepley   }
1158c717d290SMatthew G. Knepley   if (!p->section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Shell partitioner information not provided. Please call PetscPartitionerShellSetPartition()");
115977623264SMatthew G. Knepley   ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr);
116077623264SMatthew G. Knepley   if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np);
116177623264SMatthew G. Knepley   ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr);
116277623264SMatthew G. Knepley   if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np);
11635680f57bSMatthew G. Knepley   ierr = PetscSectionCopy(p->section, partSection);CHKERRQ(ierr);
116477623264SMatthew G. Knepley   *partition = p->partition;
116577623264SMatthew G. Knepley   ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr);
116677623264SMatthew G. Knepley   PetscFunctionReturn(0);
116777623264SMatthew G. Knepley }
116877623264SMatthew G. Knepley 
1169d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part)
117077623264SMatthew G. Knepley {
117177623264SMatthew G. Knepley   PetscFunctionBegin;
1172074d466cSStefano Zampini   part->noGraph             = PETSC_TRUE; /* PetscPartitionerShell cannot overload the partition call, so it is safe for now */
117377623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_Shell;
1174077101c0SMatthew G. Knepley   part->ops->setfromoptions = PetscPartitionerSetFromOptions_Shell;
117577623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_Shell;
117677623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_Shell;
117777623264SMatthew G. Knepley   PetscFunctionReturn(0);
117877623264SMatthew G. Knepley }
117977623264SMatthew G. Knepley 
118077623264SMatthew G. Knepley /*MC
118177623264SMatthew G. Knepley   PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object
118277623264SMatthew G. Knepley 
118377623264SMatthew G. Knepley   Level: intermediate
118477623264SMatthew G. Knepley 
118577623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
118677623264SMatthew G. Knepley M*/
118777623264SMatthew G. Knepley 
118877623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part)
118977623264SMatthew G. Knepley {
119077623264SMatthew G. Knepley   PetscPartitioner_Shell *p;
119177623264SMatthew G. Knepley   PetscErrorCode          ierr;
119277623264SMatthew G. Knepley 
119377623264SMatthew G. Knepley   PetscFunctionBegin;
119477623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
119577623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
119677623264SMatthew G. Knepley   part->data = p;
119777623264SMatthew G. Knepley 
119877623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr);
1199077101c0SMatthew G. Knepley   p->random = PETSC_FALSE;
120077623264SMatthew G. Knepley   PetscFunctionReturn(0);
120177623264SMatthew G. Knepley }
120277623264SMatthew G. Knepley 
12035680f57bSMatthew G. Knepley /*@C
12045680f57bSMatthew G. Knepley   PetscPartitionerShellSetPartition - Set an artifical partition for a mesh
12055680f57bSMatthew G. Knepley 
1206fe2efc57SMark   Collective on PetscPartitioner
12075680f57bSMatthew G. Knepley 
12085680f57bSMatthew G. Knepley   Input Parameters:
12095680f57bSMatthew G. Knepley + part   - The PetscPartitioner
12109852e123SBarry Smith . size   - The number of partitions
12119852e123SBarry Smith . sizes  - array of size size (or NULL) providing the number of points in each partition
12129758bf69SToby 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.)
12135680f57bSMatthew G. Knepley 
12145680f57bSMatthew G. Knepley   Level: developer
12155680f57bSMatthew G. Knepley 
1216b7e49471SLawrence Mitchell   Notes:
1217b7e49471SLawrence Mitchell 
1218b7e49471SLawrence Mitchell     It is safe to free the sizes and points arrays after use in this routine.
1219b7e49471SLawrence Mitchell 
12205680f57bSMatthew G. Knepley .seealso DMPlexDistribute(), PetscPartitionerCreate()
12215680f57bSMatthew G. Knepley @*/
12229852e123SBarry Smith PetscErrorCode PetscPartitionerShellSetPartition(PetscPartitioner part, PetscInt size, const PetscInt sizes[], const PetscInt points[])
12235680f57bSMatthew G. Knepley {
12245680f57bSMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
12255680f57bSMatthew G. Knepley   PetscInt                proc, numPoints;
12265680f57bSMatthew G. Knepley   PetscErrorCode          ierr;
12275680f57bSMatthew G. Knepley 
12285680f57bSMatthew G. Knepley   PetscFunctionBegin;
12295680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
12305680f57bSMatthew G. Knepley   if (sizes)  {PetscValidPointer(sizes, 3);}
1231c717d290SMatthew G. Knepley   if (points) {PetscValidPointer(points, 4);}
12325680f57bSMatthew G. Knepley   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
12335680f57bSMatthew G. Knepley   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
12345680f57bSMatthew G. Knepley   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) part), &p->section);CHKERRQ(ierr);
12359852e123SBarry Smith   ierr = PetscSectionSetChart(p->section, 0, size);CHKERRQ(ierr);
12365680f57bSMatthew G. Knepley   if (sizes) {
12379852e123SBarry Smith     for (proc = 0; proc < size; ++proc) {
12385680f57bSMatthew G. Knepley       ierr = PetscSectionSetDof(p->section, proc, sizes[proc]);CHKERRQ(ierr);
12395680f57bSMatthew G. Knepley     }
12405680f57bSMatthew G. Knepley   }
12415680f57bSMatthew G. Knepley   ierr = PetscSectionSetUp(p->section);CHKERRQ(ierr);
12425680f57bSMatthew G. Knepley   ierr = PetscSectionGetStorageSize(p->section, &numPoints);CHKERRQ(ierr);
12435680f57bSMatthew G. Knepley   ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), numPoints, points, PETSC_COPY_VALUES, &p->partition);CHKERRQ(ierr);
12445680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
12455680f57bSMatthew G. Knepley }
12465680f57bSMatthew G. Knepley 
1247077101c0SMatthew G. Knepley /*@
1248077101c0SMatthew G. Knepley   PetscPartitionerShellSetRandom - Set the flag to use a random partition
1249077101c0SMatthew G. Knepley 
1250fe2efc57SMark   Collective on PetscPartitioner
1251077101c0SMatthew G. Knepley 
1252077101c0SMatthew G. Knepley   Input Parameters:
1253077101c0SMatthew G. Knepley + part   - The PetscPartitioner
1254077101c0SMatthew G. Knepley - random - The flag to use a random partition
1255077101c0SMatthew G. Knepley 
1256077101c0SMatthew G. Knepley   Level: intermediate
1257077101c0SMatthew G. Knepley 
1258077101c0SMatthew G. Knepley .seealso PetscPartitionerShellGetRandom(), PetscPartitionerCreate()
1259077101c0SMatthew G. Knepley @*/
1260077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellSetRandom(PetscPartitioner part, PetscBool random)
1261077101c0SMatthew G. Knepley {
1262077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1263077101c0SMatthew G. Knepley 
1264077101c0SMatthew G. Knepley   PetscFunctionBegin;
1265077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1266077101c0SMatthew G. Knepley   p->random = random;
1267077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1268077101c0SMatthew G. Knepley }
1269077101c0SMatthew G. Knepley 
1270077101c0SMatthew G. Knepley /*@
1271077101c0SMatthew G. Knepley   PetscPartitionerShellGetRandom - get the flag to use a random partition
1272077101c0SMatthew G. Knepley 
1273fe2efc57SMark   Collective on PetscPartitioner
1274077101c0SMatthew G. Knepley 
1275077101c0SMatthew G. Knepley   Input Parameter:
1276077101c0SMatthew G. Knepley . part   - The PetscPartitioner
1277077101c0SMatthew G. Knepley 
1278077101c0SMatthew G. Knepley   Output Parameter
1279077101c0SMatthew G. Knepley . random - The flag to use a random partition
1280077101c0SMatthew G. Knepley 
1281077101c0SMatthew G. Knepley   Level: intermediate
1282077101c0SMatthew G. Knepley 
1283077101c0SMatthew G. Knepley .seealso PetscPartitionerShellSetRandom(), PetscPartitionerCreate()
1284077101c0SMatthew G. Knepley @*/
1285077101c0SMatthew G. Knepley PetscErrorCode PetscPartitionerShellGetRandom(PetscPartitioner part, PetscBool *random)
1286077101c0SMatthew G. Knepley {
1287077101c0SMatthew G. Knepley   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
1288077101c0SMatthew G. Knepley 
1289077101c0SMatthew G. Knepley   PetscFunctionBegin;
1290077101c0SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1291077101c0SMatthew G. Knepley   PetscValidPointer(random, 2);
1292077101c0SMatthew G. Knepley   *random = p->random;
1293077101c0SMatthew G. Knepley   PetscFunctionReturn(0);
1294077101c0SMatthew G. Knepley }
1295077101c0SMatthew G. Knepley 
1296d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Simple(PetscPartitioner part)
1297555a9cf8SMatthew G. Knepley {
1298555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p = (PetscPartitioner_Simple *) part->data;
1299555a9cf8SMatthew G. Knepley   PetscErrorCode          ierr;
1300555a9cf8SMatthew G. Knepley 
1301555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1302555a9cf8SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
1303555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1304555a9cf8SMatthew G. Knepley }
1305555a9cf8SMatthew G. Knepley 
1306d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple_Ascii(PetscPartitioner part, PetscViewer viewer)
1307555a9cf8SMatthew G. Knepley {
1308555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1309555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1310555a9cf8SMatthew G. Knepley }
1311555a9cf8SMatthew G. Knepley 
1312d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Simple(PetscPartitioner part, PetscViewer viewer)
1313555a9cf8SMatthew G. Knepley {
1314555a9cf8SMatthew G. Knepley   PetscBool      iascii;
1315555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1316555a9cf8SMatthew G. Knepley 
1317555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1318555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1319555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1320555a9cf8SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1321555a9cf8SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Simple_Ascii(part, viewer);CHKERRQ(ierr);}
1322555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1323555a9cf8SMatthew G. Knepley }
1324555a9cf8SMatthew G. Knepley 
1325d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Simple(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1326555a9cf8SMatthew G. Knepley {
1327cead94edSToby Isaac   MPI_Comm       comm;
1328555a9cf8SMatthew G. Knepley   PetscInt       np;
1329cead94edSToby Isaac   PetscMPIInt    size;
1330555a9cf8SMatthew G. Knepley   PetscErrorCode ierr;
1331555a9cf8SMatthew G. Knepley 
1332555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
133304ba2274SStefano Zampini   comm = PetscObjectComm((PetscObject)part);
1334cead94edSToby Isaac   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1335555a9cf8SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1336555a9cf8SMatthew G. Knepley   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1337cead94edSToby Isaac   if (size == 1) {
1338cead94edSToby Isaac     for (np = 0; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, numVertices/nparts + ((numVertices % nparts) > np));CHKERRQ(ierr);}
133904ba2274SStefano Zampini   } else {
1340cead94edSToby Isaac     PetscMPIInt rank;
1341cead94edSToby Isaac     PetscInt nvGlobal, *offsets, myFirst, myLast;
1342cead94edSToby Isaac 
1343a679a563SToby Isaac     ierr = PetscMalloc1(size+1,&offsets);CHKERRQ(ierr);
1344cead94edSToby Isaac     offsets[0] = 0;
1345cead94edSToby Isaac     ierr = MPI_Allgather(&numVertices,1,MPIU_INT,&offsets[1],1,MPIU_INT,comm);CHKERRQ(ierr);
1346cead94edSToby Isaac     for (np = 2; np <= size; np++) {
1347cead94edSToby Isaac       offsets[np] += offsets[np-1];
1348cead94edSToby Isaac     }
1349cead94edSToby Isaac     nvGlobal = offsets[size];
1350cead94edSToby Isaac     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1351cead94edSToby Isaac     myFirst = offsets[rank];
1352cead94edSToby Isaac     myLast  = offsets[rank + 1] - 1;
1353cead94edSToby Isaac     ierr = PetscFree(offsets);CHKERRQ(ierr);
1354cead94edSToby Isaac     if (numVertices) {
1355cead94edSToby Isaac       PetscInt firstPart = 0, firstLargePart = 0;
1356cead94edSToby Isaac       PetscInt lastPart = 0, lastLargePart = 0;
1357cead94edSToby Isaac       PetscInt rem = nvGlobal % nparts;
1358cead94edSToby Isaac       PetscInt pSmall = nvGlobal/nparts;
1359cead94edSToby Isaac       PetscInt pBig = nvGlobal/nparts + 1;
1360cead94edSToby Isaac 
1361cead94edSToby Isaac 
1362cead94edSToby Isaac       if (rem) {
1363cead94edSToby Isaac         firstLargePart = myFirst / pBig;
1364cead94edSToby Isaac         lastLargePart  = myLast  / pBig;
1365cead94edSToby Isaac 
1366cead94edSToby Isaac         if (firstLargePart < rem) {
1367cead94edSToby Isaac           firstPart = firstLargePart;
136804ba2274SStefano Zampini         } else {
1369cead94edSToby Isaac           firstPart = rem + (myFirst - (rem * pBig)) / pSmall;
1370cead94edSToby Isaac         }
1371cead94edSToby Isaac         if (lastLargePart < rem) {
1372cead94edSToby Isaac           lastPart = lastLargePart;
137304ba2274SStefano Zampini         } else {
1374cead94edSToby Isaac           lastPart = rem + (myLast - (rem * pBig)) / pSmall;
1375cead94edSToby Isaac         }
137604ba2274SStefano Zampini       } else {
1377cead94edSToby Isaac         firstPart = myFirst / (nvGlobal/nparts);
1378cead94edSToby Isaac         lastPart  = myLast  / (nvGlobal/nparts);
1379cead94edSToby Isaac       }
1380cead94edSToby Isaac 
1381cead94edSToby Isaac       for (np = firstPart; np <= lastPart; np++) {
1382cead94edSToby Isaac         PetscInt PartStart =  np    * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np);
1383cead94edSToby Isaac         PetscInt PartEnd   = (np+1) * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np+1);
1384cead94edSToby Isaac 
1385cead94edSToby Isaac         PartStart = PetscMax(PartStart,myFirst);
1386cead94edSToby Isaac         PartEnd   = PetscMin(PartEnd,myLast+1);
1387cead94edSToby Isaac         ierr = PetscSectionSetDof(partSection,np,PartEnd-PartStart);CHKERRQ(ierr);
1388cead94edSToby Isaac       }
1389cead94edSToby Isaac     }
1390cead94edSToby Isaac   }
1391cead94edSToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1392555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1393555a9cf8SMatthew G. Knepley }
1394555a9cf8SMatthew G. Knepley 
1395d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Simple(PetscPartitioner part)
1396555a9cf8SMatthew G. Knepley {
1397555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1398074d466cSStefano Zampini   part->noGraph        = PETSC_TRUE;
1399555a9cf8SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Simple;
1400555a9cf8SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Simple;
1401555a9cf8SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Simple;
1402555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1403555a9cf8SMatthew G. Knepley }
1404555a9cf8SMatthew G. Knepley 
1405555a9cf8SMatthew G. Knepley /*MC
1406555a9cf8SMatthew G. Knepley   PETSCPARTITIONERSIMPLE = "simple" - A PetscPartitioner object
1407555a9cf8SMatthew G. Knepley 
1408555a9cf8SMatthew G. Knepley   Level: intermediate
1409555a9cf8SMatthew G. Knepley 
1410555a9cf8SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1411555a9cf8SMatthew G. Knepley M*/
1412555a9cf8SMatthew G. Knepley 
1413555a9cf8SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Simple(PetscPartitioner part)
1414555a9cf8SMatthew G. Knepley {
1415555a9cf8SMatthew G. Knepley   PetscPartitioner_Simple *p;
1416555a9cf8SMatthew G. Knepley   PetscErrorCode           ierr;
1417555a9cf8SMatthew G. Knepley 
1418555a9cf8SMatthew G. Knepley   PetscFunctionBegin;
1419555a9cf8SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1420555a9cf8SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1421555a9cf8SMatthew G. Knepley   part->data = p;
1422555a9cf8SMatthew G. Knepley 
1423555a9cf8SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Simple(part);CHKERRQ(ierr);
1424555a9cf8SMatthew G. Knepley   PetscFunctionReturn(0);
1425555a9cf8SMatthew G. Knepley }
1426555a9cf8SMatthew G. Knepley 
1427d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Gather(PetscPartitioner part)
1428dae52e14SToby Isaac {
1429dae52e14SToby Isaac   PetscPartitioner_Gather *p = (PetscPartitioner_Gather *) part->data;
1430dae52e14SToby Isaac   PetscErrorCode          ierr;
1431dae52e14SToby Isaac 
1432dae52e14SToby Isaac   PetscFunctionBegin;
1433dae52e14SToby Isaac   ierr = PetscFree(p);CHKERRQ(ierr);
1434dae52e14SToby Isaac   PetscFunctionReturn(0);
1435dae52e14SToby Isaac }
1436dae52e14SToby Isaac 
1437d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather_Ascii(PetscPartitioner part, PetscViewer viewer)
1438dae52e14SToby Isaac {
1439dae52e14SToby Isaac   PetscFunctionBegin;
1440dae52e14SToby Isaac   PetscFunctionReturn(0);
1441dae52e14SToby Isaac }
1442dae52e14SToby Isaac 
1443d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Gather(PetscPartitioner part, PetscViewer viewer)
1444dae52e14SToby Isaac {
1445dae52e14SToby Isaac   PetscBool      iascii;
1446dae52e14SToby Isaac   PetscErrorCode ierr;
1447dae52e14SToby Isaac 
1448dae52e14SToby Isaac   PetscFunctionBegin;
1449dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1450dae52e14SToby Isaac   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1451dae52e14SToby Isaac   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1452dae52e14SToby Isaac   if (iascii) {ierr = PetscPartitionerView_Gather_Ascii(part, viewer);CHKERRQ(ierr);}
1453dae52e14SToby Isaac   PetscFunctionReturn(0);
1454dae52e14SToby Isaac }
1455dae52e14SToby Isaac 
1456d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Gather(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1457dae52e14SToby Isaac {
1458dae52e14SToby Isaac   PetscInt       np;
1459dae52e14SToby Isaac   PetscErrorCode ierr;
1460dae52e14SToby Isaac 
1461dae52e14SToby Isaac   PetscFunctionBegin;
1462dae52e14SToby Isaac   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1463dae52e14SToby Isaac   ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr);
1464dae52e14SToby Isaac   ierr = PetscSectionSetDof(partSection,0,numVertices);CHKERRQ(ierr);
1465dae52e14SToby Isaac   for (np = 1; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, 0);CHKERRQ(ierr);}
1466dae52e14SToby Isaac   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1467dae52e14SToby Isaac   PetscFunctionReturn(0);
1468dae52e14SToby Isaac }
1469dae52e14SToby Isaac 
1470d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Gather(PetscPartitioner part)
1471dae52e14SToby Isaac {
1472dae52e14SToby Isaac   PetscFunctionBegin;
1473074d466cSStefano Zampini   part->noGraph        = PETSC_TRUE;
1474dae52e14SToby Isaac   part->ops->view      = PetscPartitionerView_Gather;
1475dae52e14SToby Isaac   part->ops->destroy   = PetscPartitionerDestroy_Gather;
1476dae52e14SToby Isaac   part->ops->partition = PetscPartitionerPartition_Gather;
1477dae52e14SToby Isaac   PetscFunctionReturn(0);
1478dae52e14SToby Isaac }
1479dae52e14SToby Isaac 
1480dae52e14SToby Isaac /*MC
1481dae52e14SToby Isaac   PETSCPARTITIONERGATHER = "gather" - A PetscPartitioner object
1482dae52e14SToby Isaac 
1483dae52e14SToby Isaac   Level: intermediate
1484dae52e14SToby Isaac 
1485dae52e14SToby Isaac .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1486dae52e14SToby Isaac M*/
1487dae52e14SToby Isaac 
1488dae52e14SToby Isaac PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Gather(PetscPartitioner part)
1489dae52e14SToby Isaac {
1490dae52e14SToby Isaac   PetscPartitioner_Gather *p;
1491dae52e14SToby Isaac   PetscErrorCode           ierr;
1492dae52e14SToby Isaac 
1493dae52e14SToby Isaac   PetscFunctionBegin;
1494dae52e14SToby Isaac   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1495dae52e14SToby Isaac   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1496dae52e14SToby Isaac   part->data = p;
1497dae52e14SToby Isaac 
1498dae52e14SToby Isaac   ierr = PetscPartitionerInitialize_Gather(part);CHKERRQ(ierr);
1499dae52e14SToby Isaac   PetscFunctionReturn(0);
1500dae52e14SToby Isaac }
1501dae52e14SToby Isaac 
1502dae52e14SToby Isaac 
1503d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part)
150477623264SMatthew G. Knepley {
150577623264SMatthew G. Knepley   PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data;
150677623264SMatthew G. Knepley   PetscErrorCode          ierr;
150777623264SMatthew G. Knepley 
150877623264SMatthew G. Knepley   PetscFunctionBegin;
150977623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
151077623264SMatthew G. Knepley   PetscFunctionReturn(0);
151177623264SMatthew G. Knepley }
151277623264SMatthew G. Knepley 
1513d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer)
151477623264SMatthew G. Knepley {
151577623264SMatthew G. Knepley   PetscFunctionBegin;
151677623264SMatthew G. Knepley   PetscFunctionReturn(0);
151777623264SMatthew G. Knepley }
151877623264SMatthew G. Knepley 
1519d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer)
152077623264SMatthew G. Knepley {
152177623264SMatthew G. Knepley   PetscBool      iascii;
152277623264SMatthew G. Knepley   PetscErrorCode ierr;
152377623264SMatthew G. Knepley 
152477623264SMatthew G. Knepley   PetscFunctionBegin;
152577623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
152677623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
152777623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
152877623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);}
152977623264SMatthew G. Knepley   PetscFunctionReturn(0);
153077623264SMatthew G. Knepley }
153177623264SMatthew G. Knepley 
153270034214SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
153370034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
153470034214SMatthew G. Knepley #include <unistd.h>
153570034214SMatthew G. Knepley #endif
153611d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
153711d1e910SBarry Smith #include <chaco.h>
153811d1e910SBarry Smith #else
153911d1e910SBarry Smith /* Older versions of Chaco do not have an include file */
154070034214SMatthew G. Knepley PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
154170034214SMatthew G. Knepley                        float *ewgts, float *x, float *y, float *z, char *outassignname,
154270034214SMatthew G. Knepley                        char *outfilename, short *assignment, int architecture, int ndims_tot,
154370034214SMatthew G. Knepley                        int mesh_dims[3], double *goal, int global_method, int local_method,
154470034214SMatthew G. Knepley                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
154511d1e910SBarry Smith #endif
154670034214SMatthew G. Knepley extern int FREE_GRAPH;
154777623264SMatthew G. Knepley #endif
154870034214SMatthew G. Knepley 
1549d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
155070034214SMatthew G. Knepley {
155177623264SMatthew G. Knepley #if defined(PETSC_HAVE_CHACO)
155270034214SMatthew G. Knepley   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
155370034214SMatthew G. Knepley   MPI_Comm       comm;
155470034214SMatthew G. Knepley   int            nvtxs          = numVertices; /* number of vertices in full graph */
155570034214SMatthew G. Knepley   int           *vwgts          = NULL;   /* weights for all vertices */
155670034214SMatthew G. Knepley   float         *ewgts          = NULL;   /* weights for all edges */
155770034214SMatthew G. Knepley   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
155870034214SMatthew G. Knepley   char          *outassignname  = NULL;   /*  name of assignment output file */
155970034214SMatthew G. Knepley   char          *outfilename    = NULL;   /* output file name */
156070034214SMatthew G. Knepley   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
156170034214SMatthew G. Knepley   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
156270034214SMatthew G. Knepley   int            mesh_dims[3];            /* dimensions of mesh of processors */
156370034214SMatthew G. Knepley   double        *goal          = NULL;    /* desired set sizes for each set */
156470034214SMatthew G. Knepley   int            global_method = 1;       /* global partitioning algorithm */
156570034214SMatthew G. Knepley   int            local_method  = 1;       /* local partitioning algorithm */
156670034214SMatthew G. Knepley   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
156770034214SMatthew G. Knepley   int            vmax          = 200;     /* how many vertices to coarsen down to? */
156870034214SMatthew G. Knepley   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
156970034214SMatthew G. Knepley   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
157070034214SMatthew G. Knepley   long           seed          = 123636512; /* for random graph mutations */
157111d1e910SBarry Smith #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT)
157211d1e910SBarry Smith   int           *assignment;              /* Output partition */
157311d1e910SBarry Smith #else
157470034214SMatthew G. Knepley   short int     *assignment;              /* Output partition */
157511d1e910SBarry Smith #endif
157670034214SMatthew G. Knepley   int            fd_stdout, fd_pipe[2];
157770034214SMatthew G. Knepley   PetscInt      *points;
157870034214SMatthew G. Knepley   int            i, v, p;
157970034214SMatthew G. Knepley   PetscErrorCode ierr;
158070034214SMatthew G. Knepley 
158170034214SMatthew G. Knepley   PetscFunctionBegin;
158270034214SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
158307ed3857SLisandro Dalcin #if defined (PETSC_USE_DEBUG)
158407ed3857SLisandro Dalcin   {
158507ed3857SLisandro Dalcin     int ival,isum;
158607ed3857SLisandro Dalcin     PetscBool distributed;
158707ed3857SLisandro Dalcin 
158807ed3857SLisandro Dalcin     ival = (numVertices > 0);
158907ed3857SLisandro Dalcin     ierr = MPI_Allreduce(&ival, &isum, 1, MPI_INT, MPI_SUM, comm);CHKERRQ(ierr);
159007ed3857SLisandro Dalcin     distributed = (isum > 1) ? PETSC_TRUE : PETSC_FALSE;
159107ed3857SLisandro Dalcin     if (distributed) SETERRQ(comm, PETSC_ERR_SUP, "Chaco cannot partition a distributed graph");
159207ed3857SLisandro Dalcin   }
159307ed3857SLisandro Dalcin #endif
159470034214SMatthew G. Knepley   if (!numVertices) {
159577623264SMatthew G. Knepley     ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
159677623264SMatthew G. Knepley     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
159770034214SMatthew G. Knepley     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
159870034214SMatthew G. Knepley     PetscFunctionReturn(0);
159970034214SMatthew G. Knepley   }
160070034214SMatthew G. Knepley   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
160170034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
160270034214SMatthew G. Knepley 
160370034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
160470034214SMatthew G. Knepley     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
160570034214SMatthew G. Knepley     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
160670034214SMatthew G. Knepley   }
160777623264SMatthew G. Knepley   mesh_dims[0] = nparts;
160870034214SMatthew G. Knepley   mesh_dims[1] = 1;
160970034214SMatthew G. Knepley   mesh_dims[2] = 1;
161070034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr);
161170034214SMatthew G. Knepley   /* Chaco outputs to stdout. We redirect this to a buffer. */
161270034214SMatthew G. Knepley   /* TODO: check error codes for UNIX calls */
161370034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
161470034214SMatthew G. Knepley   {
161570034214SMatthew G. Knepley     int piperet;
161670034214SMatthew G. Knepley     piperet = pipe(fd_pipe);
161770034214SMatthew G. Knepley     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
161870034214SMatthew G. Knepley     fd_stdout = dup(1);
161970034214SMatthew G. Knepley     close(1);
162070034214SMatthew G. Knepley     dup2(fd_pipe[1], 1);
162170034214SMatthew G. Knepley   }
162270034214SMatthew G. Knepley #endif
162370034214SMatthew G. Knepley   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
162470034214SMatthew G. Knepley                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
162570034214SMatthew G. Knepley                    vmax, ndims, eigtol, seed);
162670034214SMatthew G. Knepley #if defined(PETSC_HAVE_UNISTD_H)
162770034214SMatthew G. Knepley   {
162870034214SMatthew G. Knepley     char msgLog[10000];
162970034214SMatthew G. Knepley     int  count;
163070034214SMatthew G. Knepley 
163170034214SMatthew G. Knepley     fflush(stdout);
163270034214SMatthew G. Knepley     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
163370034214SMatthew G. Knepley     if (count < 0) count = 0;
163470034214SMatthew G. Knepley     msgLog[count] = 0;
163570034214SMatthew G. Knepley     close(1);
163670034214SMatthew G. Knepley     dup2(fd_stdout, 1);
163770034214SMatthew G. Knepley     close(fd_stdout);
163870034214SMatthew G. Knepley     close(fd_pipe[0]);
163970034214SMatthew G. Knepley     close(fd_pipe[1]);
164070034214SMatthew G. Knepley     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
164170034214SMatthew G. Knepley   }
164207ed3857SLisandro Dalcin #else
164307ed3857SLisandro Dalcin   if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", "error in stdout");
164470034214SMatthew G. Knepley #endif
164570034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
164677623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
164770034214SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {
164877623264SMatthew G. Knepley     ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);
164970034214SMatthew G. Knepley   }
165077623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
165170034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
165277623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
165370034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
165470034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
165570034214SMatthew G. Knepley     }
165670034214SMatthew G. Knepley   }
165770034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
165870034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
165970034214SMatthew G. Knepley   if (global_method == INERTIAL_METHOD) {
166070034214SMatthew G. Knepley     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
166170034214SMatthew G. Knepley   }
166270034214SMatthew G. Knepley   ierr = PetscFree(assignment);CHKERRQ(ierr);
166370034214SMatthew G. Knepley   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
166470034214SMatthew G. Knepley   PetscFunctionReturn(0);
166577623264SMatthew G. Knepley #else
166677623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
166770034214SMatthew G. Knepley #endif
166877623264SMatthew G. Knepley }
166977623264SMatthew G. Knepley 
1670d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part)
167177623264SMatthew G. Knepley {
167277623264SMatthew G. Knepley   PetscFunctionBegin;
1673074d466cSStefano Zampini   part->noGraph        = PETSC_FALSE;
167477623264SMatthew G. Knepley   part->ops->view      = PetscPartitionerView_Chaco;
167577623264SMatthew G. Knepley   part->ops->destroy   = PetscPartitionerDestroy_Chaco;
167677623264SMatthew G. Knepley   part->ops->partition = PetscPartitionerPartition_Chaco;
167777623264SMatthew G. Knepley   PetscFunctionReturn(0);
167877623264SMatthew G. Knepley }
167977623264SMatthew G. Knepley 
168077623264SMatthew G. Knepley /*MC
168177623264SMatthew G. Knepley   PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library
168277623264SMatthew G. Knepley 
168377623264SMatthew G. Knepley   Level: intermediate
168477623264SMatthew G. Knepley 
168577623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
168677623264SMatthew G. Knepley M*/
168777623264SMatthew G. Knepley 
168877623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part)
168977623264SMatthew G. Knepley {
169077623264SMatthew G. Knepley   PetscPartitioner_Chaco *p;
169177623264SMatthew G. Knepley   PetscErrorCode          ierr;
169277623264SMatthew G. Knepley 
169377623264SMatthew G. Knepley   PetscFunctionBegin;
169477623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
169577623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
169677623264SMatthew G. Knepley   part->data = p;
169777623264SMatthew G. Knepley 
169877623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr);
169977623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr);
170077623264SMatthew G. Knepley   PetscFunctionReturn(0);
170177623264SMatthew G. Knepley }
170277623264SMatthew G. Knepley 
17035b440754SMatthew G. Knepley static const char *ptypes[] = {"kway", "rb"};
17045b440754SMatthew G. Knepley 
1705d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part)
170677623264SMatthew G. Knepley {
170777623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
170877623264SMatthew G. Knepley   PetscErrorCode             ierr;
170977623264SMatthew G. Knepley 
171077623264SMatthew G. Knepley   PetscFunctionBegin;
171177623264SMatthew G. Knepley   ierr = PetscFree(p);CHKERRQ(ierr);
171277623264SMatthew G. Knepley   PetscFunctionReturn(0);
171377623264SMatthew G. Knepley }
171477623264SMatthew G. Knepley 
1715d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer)
171677623264SMatthew G. Knepley {
17172abdaa70SMatthew G. Knepley   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
171877623264SMatthew G. Knepley   PetscErrorCode             ierr;
171977623264SMatthew G. Knepley 
172077623264SMatthew G. Knepley   PetscFunctionBegin;
17212abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
17222abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "ParMetis type: %s\n", ptypes[p->ptype]);CHKERRQ(ierr);
17232abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "load imbalance ratio %g\n", (double) p->imbalanceRatio);CHKERRQ(ierr);
17242abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPrintf(viewer, "debug flag %D\n", p->debugFlag);CHKERRQ(ierr);
17259d459c0eSStefano Zampini   ierr = PetscViewerASCIIPrintf(viewer, "random seed %D\n", p->randomSeed);CHKERRQ(ierr);
17262abdaa70SMatthew G. Knepley   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
172777623264SMatthew G. Knepley   PetscFunctionReturn(0);
172877623264SMatthew G. Knepley }
172977623264SMatthew G. Knepley 
1730d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer)
173177623264SMatthew G. Knepley {
173277623264SMatthew G. Knepley   PetscBool      iascii;
173377623264SMatthew G. Knepley   PetscErrorCode ierr;
173477623264SMatthew G. Knepley 
173577623264SMatthew G. Knepley   PetscFunctionBegin;
173677623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
173777623264SMatthew G. Knepley   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
173877623264SMatthew G. Knepley   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
173977623264SMatthew G. Knepley   if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);}
174077623264SMatthew G. Knepley   PetscFunctionReturn(0);
174177623264SMatthew G. Knepley }
174270034214SMatthew G. Knepley 
174344d8be81SLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_ParMetis(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
174444d8be81SLisandro Dalcin {
174544d8be81SLisandro Dalcin   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
174644d8be81SLisandro Dalcin   PetscErrorCode            ierr;
174744d8be81SLisandro Dalcin 
174844d8be81SLisandro Dalcin   PetscFunctionBegin;
174944d8be81SLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner ParMetis Options");CHKERRQ(ierr);
175044d8be81SLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_parmetis_type", "Partitioning method", "", ptypes, 2, ptypes[p->ptype], &p->ptype, NULL);CHKERRQ(ierr);
17515b440754SMatthew G. Knepley   ierr = PetscOptionsReal("-petscpartitioner_parmetis_imbalance_ratio", "Load imbalance ratio limit", "", p->imbalanceRatio, &p->imbalanceRatio, NULL);CHKERRQ(ierr);
17525b440754SMatthew G. Knepley   ierr = PetscOptionsInt("-petscpartitioner_parmetis_debug", "Debugging flag", "", p->debugFlag, &p->debugFlag, NULL);CHKERRQ(ierr);
17539d459c0eSStefano Zampini   ierr = PetscOptionsInt("-petscpartitioner_parmetis_seed", "Random seed", "", p->randomSeed, &p->randomSeed, NULL);CHKERRQ(ierr);
175444d8be81SLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
175544d8be81SLisandro Dalcin   PetscFunctionReturn(0);
175644d8be81SLisandro Dalcin }
175744d8be81SLisandro Dalcin 
175870034214SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
175970034214SMatthew G. Knepley #include <parmetis.h>
176077623264SMatthew G. Knepley #endif
176170034214SMatthew G. Knepley 
1762d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
176370034214SMatthew G. Knepley {
176477623264SMatthew G. Knepley #if defined(PETSC_HAVE_PARMETIS)
17655b440754SMatthew G. Knepley   PetscPartitioner_ParMetis *pm = (PetscPartitioner_ParMetis *) part->data;
176670034214SMatthew G. Knepley   MPI_Comm       comm;
1767deea36a5SMatthew G. Knepley   PetscSection   section;
176870034214SMatthew G. Knepley   PetscInt       nvtxs       = numVertices; /* The number of vertices in full graph */
176970034214SMatthew G. Knepley   PetscInt      *vtxdist;                   /* Distribution of vertices across processes */
177070034214SMatthew G. Knepley   PetscInt      *xadj        = start;       /* Start of edge list for each vertex */
177170034214SMatthew G. Knepley   PetscInt      *adjncy      = adjacency;   /* Edge lists for all vertices */
177270034214SMatthew G. Knepley   PetscInt      *vwgt        = NULL;        /* Vertex weights */
177370034214SMatthew G. Knepley   PetscInt      *adjwgt      = NULL;        /* Edge weights */
177470034214SMatthew G. Knepley   PetscInt       wgtflag     = 0;           /* Indicates which weights are present */
177570034214SMatthew G. Knepley   PetscInt       numflag     = 0;           /* Indicates initial offset (0 or 1) */
177670034214SMatthew G. Knepley   PetscInt       ncon        = 1;           /* The number of weights per vertex */
17775b440754SMatthew G. Knepley   PetscInt       metis_ptype = pm->ptype;   /* kway or recursive bisection */
1778fb83b9f2SMichael Gegg   real_t        *tpwgts;                    /* The fraction of vertex weights assigned to each partition */
1779fb83b9f2SMichael Gegg   real_t        *ubvec;                     /* The balance intolerance for vertex weights */
1780b3ce585bSLisandro Dalcin   PetscInt       options[64];               /* Options */
178170034214SMatthew G. Knepley   /* Outputs */
1782b3ce585bSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
1783b3ce585bSLisandro Dalcin   PetscMPIInt    size, rank, p;
178470034214SMatthew G. Knepley   PetscErrorCode ierr;
178570034214SMatthew G. Knepley 
178670034214SMatthew G. Knepley   PetscFunctionBegin;
178777623264SMatthew G. Knepley   ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr);
1788b3ce585bSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
178970034214SMatthew G. Knepley   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
179070034214SMatthew G. Knepley   /* Calculate vertex distribution */
1791b3ce585bSLisandro Dalcin   ierr = PetscMalloc5(size+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment,nvtxs,&vwgt);CHKERRQ(ierr);
179270034214SMatthew G. Knepley   vtxdist[0] = 0;
179370034214SMatthew G. Knepley   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
1794b3ce585bSLisandro Dalcin   for (p = 2; p <= size; ++p) {
179570034214SMatthew G. Knepley     vtxdist[p] += vtxdist[p-1];
179670034214SMatthew G. Knepley   }
179744d8be81SLisandro Dalcin   /* Calculate partition weights */
179870034214SMatthew G. Knepley   for (p = 0; p < nparts; ++p) {
179970034214SMatthew G. Knepley     tpwgts[p] = 1.0/nparts;
180070034214SMatthew G. Knepley   }
18015b440754SMatthew G. Knepley   ubvec[0] = pm->imbalanceRatio;
1802deea36a5SMatthew G. Knepley   /* Weight cells by dofs on cell by default */
180392fd8e1eSJed Brown   ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
18048ef05d33SStefano Zampini   for (v = 0; v < nvtxs; ++v) vwgt[v] = 1;
1805deea36a5SMatthew G. Knepley   if (section) {
1806deea36a5SMatthew G. Knepley     PetscInt cStart, cEnd, dof;
180770034214SMatthew G. Knepley 
1808925b1076SLisandro Dalcin     /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
1809925b1076SLisandro Dalcin     /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
18108ef05d33SStefano Zampini     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
18118ef05d33SStefano Zampini     for (v = cStart; v < cStart + numVertices; ++v) {
18128ef05d33SStefano Zampini       ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
18138ef05d33SStefano Zampini       vwgt[v-cStart] = PetscMax(dof, 1);
1814deea36a5SMatthew G. Knepley     }
1815cd0de0f2SShri   }
181644d8be81SLisandro Dalcin   wgtflag |= 2; /* have weights on graph vertices */
1817cd0de0f2SShri 
181870034214SMatthew G. Knepley   if (nparts == 1) {
1819580bdb30SBarry Smith     ierr = PetscArrayzero(assignment, nvtxs);CHKERRQ(ierr);
182070034214SMatthew G. Knepley   } else {
1821b3ce585bSLisandro Dalcin     for (p = 0; !vtxdist[p+1] && p < size; ++p);
1822b3ce585bSLisandro Dalcin     if (vtxdist[p+1] == vtxdist[size]) {
1823b3ce585bSLisandro Dalcin       if (rank == p) {
182444d8be81SLisandro Dalcin         ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
182542678178SLisandro Dalcin         options[METIS_OPTION_DBGLVL] = pm->debugFlag;
18269d459c0eSStefano Zampini         options[METIS_OPTION_SEED]   = pm->randomSeed;
182744d8be81SLisandro Dalcin         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
182844d8be81SLisandro Dalcin         if (metis_ptype == 1) {
182944d8be81SLisandro Dalcin           PetscStackPush("METIS_PartGraphRecursive");
183072379da4SMatthew G. Knepley           ierr = METIS_PartGraphRecursive(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
183144d8be81SLisandro Dalcin           PetscStackPop;
183244d8be81SLisandro Dalcin           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphRecursive()");
183344d8be81SLisandro Dalcin         } else {
183444d8be81SLisandro Dalcin           /*
183544d8be81SLisandro Dalcin            It would be nice to activate the two options below, but they would need some actual testing.
183644d8be81SLisandro Dalcin            - Turning on these options may exercise path of the METIS code that have bugs and may break production runs.
183744d8be81SLisandro Dalcin            - If CONTIG is set to 1, METIS will exit with error if the graph is disconnected, despite the manual saying the option is ignored in such case.
183844d8be81SLisandro Dalcin           */
183944d8be81SLisandro Dalcin           /* options[METIS_OPTION_CONTIG]  = 1; */ /* try to produce partitions that are contiguous */
184044d8be81SLisandro Dalcin           /* options[METIS_OPTION_MINCONN] = 1; */ /* minimize the maximum degree of the subdomain graph */
184170034214SMatthew G. Knepley           PetscStackPush("METIS_PartGraphKway");
184272379da4SMatthew G. Knepley           ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment);
184370034214SMatthew G. Knepley           PetscStackPop;
184470034214SMatthew G. Knepley           if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
184570034214SMatthew G. Knepley         }
184644d8be81SLisandro Dalcin       }
184770034214SMatthew G. Knepley     } else {
184842678178SLisandro Dalcin       options[0] = 1; /*use options */
18495b440754SMatthew G. Knepley       options[1] = pm->debugFlag;
18509d459c0eSStefano Zampini       options[2] = (pm->randomSeed == -1) ? 15 : pm->randomSeed; /* default is GLOBAL_SEED=15 from `libparmetis/defs.h` */
185170034214SMatthew G. Knepley       PetscStackPush("ParMETIS_V3_PartKway");
185272379da4SMatthew G. Knepley       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &part->edgeCut, assignment, &comm);
185370034214SMatthew G. Knepley       PetscStackPop;
1854c717d290SMatthew G. Knepley       if (ierr != METIS_OK) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error %d in ParMETIS_V3_PartKway()", ierr);
185570034214SMatthew G. Knepley     }
185670034214SMatthew G. Knepley   }
185770034214SMatthew G. Knepley   /* Convert to PetscSection+IS */
185877623264SMatthew G. Knepley   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
185977623264SMatthew G. Knepley   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
186077623264SMatthew G. Knepley   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
186170034214SMatthew G. Knepley   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
186277623264SMatthew G. Knepley   for (p = 0, i = 0; p < nparts; ++p) {
186370034214SMatthew G. Knepley     for (v = 0; v < nvtxs; ++v) {
186470034214SMatthew G. Knepley       if (assignment[v] == p) points[i++] = v;
186570034214SMatthew G. Knepley     }
186670034214SMatthew G. Knepley   }
186770034214SMatthew G. Knepley   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
186870034214SMatthew G. Knepley   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
1869cd0de0f2SShri   ierr = PetscFree5(vtxdist,tpwgts,ubvec,assignment,vwgt);CHKERRQ(ierr);
18709b80ac48SMatthew G. Knepley   PetscFunctionReturn(0);
187170034214SMatthew G. Knepley #else
187277623264SMatthew G. Knepley   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
187370034214SMatthew G. Knepley #endif
187470034214SMatthew G. Knepley }
187570034214SMatthew G. Knepley 
1876d5577e40SMatthew G. Knepley static PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part)
187777623264SMatthew G. Knepley {
187877623264SMatthew G. Knepley   PetscFunctionBegin;
1879074d466cSStefano Zampini   part->noGraph             = PETSC_FALSE;
188077623264SMatthew G. Knepley   part->ops->view           = PetscPartitionerView_ParMetis;
188144d8be81SLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_ParMetis;
188277623264SMatthew G. Knepley   part->ops->destroy        = PetscPartitionerDestroy_ParMetis;
188377623264SMatthew G. Knepley   part->ops->partition      = PetscPartitionerPartition_ParMetis;
188477623264SMatthew G. Knepley   PetscFunctionReturn(0);
188577623264SMatthew G. Knepley }
188677623264SMatthew G. Knepley 
188777623264SMatthew G. Knepley /*MC
188877623264SMatthew G. Knepley   PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMetis library
188977623264SMatthew G. Knepley 
189077623264SMatthew G. Knepley   Level: intermediate
189177623264SMatthew G. Knepley 
189277623264SMatthew G. Knepley .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
189377623264SMatthew G. Knepley M*/
189477623264SMatthew G. Knepley 
189577623264SMatthew G. Knepley PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part)
189677623264SMatthew G. Knepley {
189777623264SMatthew G. Knepley   PetscPartitioner_ParMetis *p;
189877623264SMatthew G. Knepley   PetscErrorCode          ierr;
189977623264SMatthew G. Knepley 
190077623264SMatthew G. Knepley   PetscFunctionBegin;
190177623264SMatthew G. Knepley   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
190277623264SMatthew G. Knepley   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
190377623264SMatthew G. Knepley   part->data = p;
190477623264SMatthew G. Knepley 
19055b440754SMatthew G. Knepley   p->ptype          = 0;
19065b440754SMatthew G. Knepley   p->imbalanceRatio = 1.05;
19075b440754SMatthew G. Knepley   p->debugFlag      = 0;
19089d459c0eSStefano Zampini   p->randomSeed     = -1; /* defaults to GLOBAL_SEED=15 from `libparmetis/defs.h` */
19095b440754SMatthew G. Knepley 
191077623264SMatthew G. Knepley   ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr);
191177623264SMatthew G. Knepley   ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr);
191270034214SMatthew G. Knepley   PetscFunctionReturn(0);
191370034214SMatthew G. Knepley }
191470034214SMatthew G. Knepley 
1915137cd93aSLisandro Dalcin PetscBool PTScotchPartitionercite = PETSC_FALSE;
1916137cd93aSLisandro Dalcin const char PTScotchPartitionerCitation[] =
1917137cd93aSLisandro Dalcin   "@article{PTSCOTCH,\n"
1918137cd93aSLisandro Dalcin   "  author  = {C. Chevalier and F. Pellegrini},\n"
1919137cd93aSLisandro Dalcin   "  title   = {{PT-SCOTCH}: a tool for efficient parallel graph ordering},\n"
1920137cd93aSLisandro Dalcin   "  journal = {Parallel Computing},\n"
1921137cd93aSLisandro Dalcin   "  volume  = {34},\n"
1922137cd93aSLisandro Dalcin   "  number  = {6},\n"
1923137cd93aSLisandro Dalcin   "  pages   = {318--331},\n"
1924137cd93aSLisandro Dalcin   "  year    = {2008},\n"
1925137cd93aSLisandro Dalcin   "  doi     = {https://doi.org/10.1016/j.parco.2007.12.001}\n"
1926137cd93aSLisandro Dalcin   "}\n";
1927137cd93aSLisandro Dalcin 
1928137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
1929137cd93aSLisandro Dalcin 
1930137cd93aSLisandro Dalcin EXTERN_C_BEGIN
1931137cd93aSLisandro Dalcin #include <ptscotch.h>
1932137cd93aSLisandro Dalcin EXTERN_C_END
1933137cd93aSLisandro Dalcin 
1934137cd93aSLisandro Dalcin #define CHKERRPTSCOTCH(ierr) do { if (ierr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_LIB,"Error calling PT-Scotch library"); } while(0)
1935137cd93aSLisandro Dalcin 
1936137cd93aSLisandro Dalcin static int PTScotch_Strategy(PetscInt strategy)
1937137cd93aSLisandro Dalcin {
1938137cd93aSLisandro Dalcin   switch (strategy) {
1939137cd93aSLisandro Dalcin   case  0: return SCOTCH_STRATDEFAULT;
1940137cd93aSLisandro Dalcin   case  1: return SCOTCH_STRATQUALITY;
1941137cd93aSLisandro Dalcin   case  2: return SCOTCH_STRATSPEED;
1942137cd93aSLisandro Dalcin   case  3: return SCOTCH_STRATBALANCE;
1943137cd93aSLisandro Dalcin   case  4: return SCOTCH_STRATSAFETY;
1944137cd93aSLisandro Dalcin   case  5: return SCOTCH_STRATSCALABILITY;
1945137cd93aSLisandro Dalcin   case  6: return SCOTCH_STRATRECURSIVE;
1946137cd93aSLisandro Dalcin   case  7: return SCOTCH_STRATREMAP;
1947137cd93aSLisandro Dalcin   default: return SCOTCH_STRATDEFAULT;
1948137cd93aSLisandro Dalcin   }
1949137cd93aSLisandro Dalcin }
1950137cd93aSLisandro Dalcin 
1951137cd93aSLisandro Dalcin 
1952137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_Seq(SCOTCH_Num strategy, double imbalance, SCOTCH_Num n, SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
1953137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[])
1954137cd93aSLisandro Dalcin {
1955137cd93aSLisandro Dalcin   SCOTCH_Graph   grafdat;
1956137cd93aSLisandro Dalcin   SCOTCH_Strat   stradat;
1957137cd93aSLisandro Dalcin   SCOTCH_Num     vertnbr = n;
1958137cd93aSLisandro Dalcin   SCOTCH_Num     edgenbr = xadj[n];
1959137cd93aSLisandro Dalcin   SCOTCH_Num*    velotab = vtxwgt;
1960137cd93aSLisandro Dalcin   SCOTCH_Num*    edlotab = adjwgt;
1961137cd93aSLisandro Dalcin   SCOTCH_Num     flagval = strategy;
1962137cd93aSLisandro Dalcin   double         kbalval = imbalance;
1963137cd93aSLisandro Dalcin   PetscErrorCode ierr;
1964137cd93aSLisandro Dalcin 
1965137cd93aSLisandro Dalcin   PetscFunctionBegin;
1966d99a0000SVaclav Hapla   {
1967d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
1968d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
1969d99a0000SVaclav Hapla     if (!flg) velotab = NULL;
1970d99a0000SVaclav Hapla   }
1971137cd93aSLisandro Dalcin   ierr = SCOTCH_graphInit(&grafdat);CHKERRPTSCOTCH(ierr);
1972137cd93aSLisandro Dalcin   ierr = SCOTCH_graphBuild(&grafdat, 0, vertnbr, xadj, xadj + 1, velotab, NULL, edgenbr, adjncy, edlotab);CHKERRPTSCOTCH(ierr);
1973137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
1974137cd93aSLisandro Dalcin   ierr = SCOTCH_stratGraphMapBuild(&stradat, flagval, nparts, kbalval);CHKERRPTSCOTCH(ierr);
1975137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
1976137cd93aSLisandro Dalcin   ierr = SCOTCH_graphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
1977137cd93aSLisandro Dalcin #endif
1978137cd93aSLisandro Dalcin   ierr = SCOTCH_graphPart(&grafdat, nparts, &stradat, part);CHKERRPTSCOTCH(ierr);
1979137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
1980137cd93aSLisandro Dalcin   SCOTCH_graphExit(&grafdat);
1981137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
1982137cd93aSLisandro Dalcin }
1983137cd93aSLisandro Dalcin 
1984137cd93aSLisandro Dalcin static PetscErrorCode PTScotch_PartGraph_MPI(SCOTCH_Num strategy, double imbalance, SCOTCH_Num vtxdist[], SCOTCH_Num xadj[], SCOTCH_Num adjncy[],
1985137cd93aSLisandro Dalcin                                              SCOTCH_Num vtxwgt[], SCOTCH_Num adjwgt[], SCOTCH_Num nparts, SCOTCH_Num part[], MPI_Comm comm)
1986137cd93aSLisandro Dalcin {
1987137cd93aSLisandro Dalcin   PetscMPIInt     procglbnbr;
1988137cd93aSLisandro Dalcin   PetscMPIInt     proclocnum;
1989137cd93aSLisandro Dalcin   SCOTCH_Arch     archdat;
1990137cd93aSLisandro Dalcin   SCOTCH_Dgraph   grafdat;
1991137cd93aSLisandro Dalcin   SCOTCH_Dmapping mappdat;
1992137cd93aSLisandro Dalcin   SCOTCH_Strat    stradat;
1993137cd93aSLisandro Dalcin   SCOTCH_Num      vertlocnbr;
1994137cd93aSLisandro Dalcin   SCOTCH_Num      edgelocnbr;
1995137cd93aSLisandro Dalcin   SCOTCH_Num*     veloloctab = vtxwgt;
1996137cd93aSLisandro Dalcin   SCOTCH_Num*     edloloctab = adjwgt;
1997137cd93aSLisandro Dalcin   SCOTCH_Num      flagval = strategy;
1998137cd93aSLisandro Dalcin   double          kbalval = imbalance;
1999137cd93aSLisandro Dalcin   PetscErrorCode  ierr;
2000137cd93aSLisandro Dalcin 
2001137cd93aSLisandro Dalcin   PetscFunctionBegin;
2002d99a0000SVaclav Hapla   {
2003d99a0000SVaclav Hapla     PetscBool flg = PETSC_TRUE;
2004d99a0000SVaclav Hapla     ierr = PetscOptionsGetBool(NULL, NULL, "-petscpartititoner_ptscotch_vertex_weight", &flg, NULL);CHKERRQ(ierr);
2005d99a0000SVaclav Hapla     if (!flg) veloloctab = NULL;
2006d99a0000SVaclav Hapla   }
2007137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &procglbnbr);CHKERRQ(ierr);
2008137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &proclocnum);CHKERRQ(ierr);
2009137cd93aSLisandro Dalcin   vertlocnbr = vtxdist[proclocnum + 1] - vtxdist[proclocnum];
2010137cd93aSLisandro Dalcin   edgelocnbr = xadj[vertlocnbr];
2011137cd93aSLisandro Dalcin 
2012137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphInit(&grafdat, comm);CHKERRPTSCOTCH(ierr);
2013137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphBuild(&grafdat, 0, vertlocnbr, vertlocnbr, xadj, xadj + 1, veloloctab, NULL, edgelocnbr, edgelocnbr, adjncy, NULL, edloloctab);CHKERRPTSCOTCH(ierr);
2014137cd93aSLisandro Dalcin #if defined(PETSC_USE_DEBUG)
2015137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphCheck(&grafdat);CHKERRPTSCOTCH(ierr);
2016137cd93aSLisandro Dalcin #endif
2017137cd93aSLisandro Dalcin   ierr = SCOTCH_stratInit(&stradat);CHKERRPTSCOTCH(ierr);
2018137cd93aSLisandro Dalcin   ierr = SCOTCH_stratDgraphMapBuild(&stradat, flagval, procglbnbr, nparts, kbalval);CHKERRQ(ierr);
2019137cd93aSLisandro Dalcin   ierr = SCOTCH_archInit(&archdat);CHKERRPTSCOTCH(ierr);
2020137cd93aSLisandro Dalcin   ierr = SCOTCH_archCmplt(&archdat, nparts);CHKERRPTSCOTCH(ierr);
2021137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapInit(&grafdat, &mappdat, &archdat, part);CHKERRPTSCOTCH(ierr);
2022cb87ef4cSFlorian Wechsung 
2023137cd93aSLisandro Dalcin   ierr = SCOTCH_dgraphMapCompute(&grafdat, &mappdat, &stradat);CHKERRPTSCOTCH(ierr);
2024137cd93aSLisandro Dalcin   SCOTCH_dgraphMapExit(&grafdat, &mappdat);
2025137cd93aSLisandro Dalcin   SCOTCH_archExit(&archdat);
2026137cd93aSLisandro Dalcin   SCOTCH_stratExit(&stradat);
2027137cd93aSLisandro Dalcin   SCOTCH_dgraphExit(&grafdat);
2028137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2029137cd93aSLisandro Dalcin }
2030137cd93aSLisandro Dalcin 
2031137cd93aSLisandro Dalcin #endif /* PETSC_HAVE_PTSCOTCH */
2032137cd93aSLisandro Dalcin 
2033137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerDestroy_PTScotch(PetscPartitioner part)
2034137cd93aSLisandro Dalcin {
2035137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2036137cd93aSLisandro Dalcin   PetscErrorCode             ierr;
2037137cd93aSLisandro Dalcin 
2038137cd93aSLisandro Dalcin   PetscFunctionBegin;
2039137cd93aSLisandro Dalcin   ierr = PetscFree(p);CHKERRQ(ierr);
2040137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2041137cd93aSLisandro Dalcin }
2042137cd93aSLisandro Dalcin 
2043137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch_Ascii(PetscPartitioner part, PetscViewer viewer)
2044137cd93aSLisandro Dalcin {
2045137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2046137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
2047137cd93aSLisandro Dalcin 
2048137cd93aSLisandro Dalcin   PetscFunctionBegin;
2049137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
2050137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using partitioning strategy %s\n",PTScotchStrategyList[p->strategy]);CHKERRQ(ierr);
2051137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPrintf(viewer, "using load imbalance ratio %g\n",(double)p->imbalance);CHKERRQ(ierr);
2052137cd93aSLisandro Dalcin   ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
2053137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2054137cd93aSLisandro Dalcin }
2055137cd93aSLisandro Dalcin 
2056137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerView_PTScotch(PetscPartitioner part, PetscViewer viewer)
2057137cd93aSLisandro Dalcin {
2058137cd93aSLisandro Dalcin   PetscBool      iascii;
2059137cd93aSLisandro Dalcin   PetscErrorCode ierr;
2060137cd93aSLisandro Dalcin 
2061137cd93aSLisandro Dalcin   PetscFunctionBegin;
2062137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
2063137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2064137cd93aSLisandro Dalcin   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
2065137cd93aSLisandro Dalcin   if (iascii) {ierr = PetscPartitionerView_PTScotch_Ascii(part, viewer);CHKERRQ(ierr);}
2066137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2067137cd93aSLisandro Dalcin }
2068137cd93aSLisandro Dalcin 
2069137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerSetFromOptions_PTScotch(PetscOptionItems *PetscOptionsObject, PetscPartitioner part)
2070137cd93aSLisandro Dalcin {
2071137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p = (PetscPartitioner_PTScotch *) part->data;
2072137cd93aSLisandro Dalcin   const char *const         *slist = PTScotchStrategyList;
2073137cd93aSLisandro Dalcin   PetscInt                  nlist = (PetscInt)(sizeof(PTScotchStrategyList)/sizeof(PTScotchStrategyList[0]));
2074137cd93aSLisandro Dalcin   PetscBool                 flag;
2075137cd93aSLisandro Dalcin   PetscErrorCode            ierr;
2076137cd93aSLisandro Dalcin 
2077137cd93aSLisandro Dalcin   PetscFunctionBegin;
2078137cd93aSLisandro Dalcin   ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitioner PTScotch Options");CHKERRQ(ierr);
2079137cd93aSLisandro Dalcin   ierr = PetscOptionsEList("-petscpartitioner_ptscotch_strategy","Partitioning strategy","",slist,nlist,slist[p->strategy],&p->strategy,&flag);CHKERRQ(ierr);
2080137cd93aSLisandro Dalcin   ierr = PetscOptionsReal("-petscpartitioner_ptscotch_imbalance","Load imbalance ratio","",p->imbalance,&p->imbalance,&flag);CHKERRQ(ierr);
2081137cd93aSLisandro Dalcin   ierr = PetscOptionsTail();CHKERRQ(ierr);
2082137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2083137cd93aSLisandro Dalcin }
2084137cd93aSLisandro Dalcin 
2085137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerPartition_PTScotch(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
2086137cd93aSLisandro Dalcin {
2087137cd93aSLisandro Dalcin #if defined(PETSC_HAVE_PTSCOTCH)
2088137cd93aSLisandro Dalcin   MPI_Comm       comm       = PetscObjectComm((PetscObject)part);
2089137cd93aSLisandro Dalcin   PetscInt       nvtxs      = numVertices; /* The number of vertices in full graph */
2090137cd93aSLisandro Dalcin   PetscInt      *vtxdist;                  /* Distribution of vertices across processes */
2091137cd93aSLisandro Dalcin   PetscInt      *xadj       = start;       /* Start of edge list for each vertex */
2092137cd93aSLisandro Dalcin   PetscInt      *adjncy     = adjacency;   /* Edge lists for all vertices */
2093137cd93aSLisandro Dalcin   PetscInt      *vwgt       = NULL;        /* Vertex weights */
2094137cd93aSLisandro Dalcin   PetscInt      *adjwgt     = NULL;        /* Edge weights */
2095137cd93aSLisandro Dalcin   PetscInt       v, i, *assignment, *points;
2096137cd93aSLisandro Dalcin   PetscMPIInt    size, rank, p;
2097137cd93aSLisandro Dalcin   PetscErrorCode ierr;
2098137cd93aSLisandro Dalcin 
2099137cd93aSLisandro Dalcin   PetscFunctionBegin;
2100137cd93aSLisandro Dalcin   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
2101137cd93aSLisandro Dalcin   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
210299b53901SStefano Zampini   ierr = PetscMalloc2(size+1,&vtxdist,PetscMax(nvtxs,1),&assignment);CHKERRQ(ierr);
2103137cd93aSLisandro Dalcin 
2104137cd93aSLisandro Dalcin   /* Calculate vertex distribution */
2105137cd93aSLisandro Dalcin   vtxdist[0] = 0;
2106137cd93aSLisandro Dalcin   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
2107137cd93aSLisandro Dalcin   for (p = 2; p <= size; ++p) {
2108137cd93aSLisandro Dalcin     vtxdist[p] += vtxdist[p-1];
2109137cd93aSLisandro Dalcin   }
2110137cd93aSLisandro Dalcin 
2111137cd93aSLisandro Dalcin   if (nparts == 1) {
2112580bdb30SBarry Smith     ierr = PetscArrayzero(assignment, nvtxs);CHKERRQ(ierr);
21138ef05d33SStefano Zampini   } else { /* Weight cells by dofs on cell by default */
2114137cd93aSLisandro Dalcin     PetscSection section;
21158ef05d33SStefano Zampini 
2116137cd93aSLisandro Dalcin     /* WARNING: Assumes that meshes with overlap have the overlapped cells at the end of the stratum. */
2117137cd93aSLisandro Dalcin     /* To do this properly, we should use the cell numbering created in DMPlexCreatePartitionerGraph. */
21188ef05d33SStefano Zampini     ierr = PetscMalloc1(PetscMax(nvtxs,1),&vwgt);CHKERRQ(ierr);
21198ef05d33SStefano Zampini     for (v = 0; v < PetscMax(nvtxs,1); ++v) vwgt[v] = 1;
212092fd8e1eSJed Brown     ierr = DMGetLocalSection(dm, &section);CHKERRQ(ierr);
21218ef05d33SStefano Zampini     if (section) {
21228ef05d33SStefano Zampini       PetscInt vStart, vEnd, dof;
21238ef05d33SStefano Zampini       ierr = DMPlexGetHeightStratum(dm, part->height, &vStart, &vEnd);CHKERRQ(ierr);
21248ef05d33SStefano Zampini       for (v = vStart; v < vStart + numVertices; ++v) {
21258ef05d33SStefano Zampini         ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr);
21268ef05d33SStefano Zampini         vwgt[v-vStart] = PetscMax(dof, 1);
2127137cd93aSLisandro Dalcin       }
2128137cd93aSLisandro Dalcin     }
2129137cd93aSLisandro Dalcin     {
2130137cd93aSLisandro Dalcin       PetscPartitioner_PTScotch *pts = (PetscPartitioner_PTScotch *) part->data;
2131137cd93aSLisandro Dalcin       int                       strat = PTScotch_Strategy(pts->strategy);
2132137cd93aSLisandro Dalcin       double                    imbal = (double)pts->imbalance;
2133137cd93aSLisandro Dalcin 
2134137cd93aSLisandro Dalcin       for (p = 0; !vtxdist[p+1] && p < size; ++p);
2135137cd93aSLisandro Dalcin       if (vtxdist[p+1] == vtxdist[size]) {
2136137cd93aSLisandro Dalcin         if (rank == p) {
2137137cd93aSLisandro Dalcin           ierr = PTScotch_PartGraph_Seq(strat, imbal, nvtxs, xadj, adjncy, vwgt, adjwgt, nparts, assignment);CHKERRQ(ierr);
2138137cd93aSLisandro Dalcin         }
2139137cd93aSLisandro Dalcin       } else {
2140137cd93aSLisandro Dalcin         ierr = PTScotch_PartGraph_MPI(strat, imbal, vtxdist, xadj, adjncy, vwgt, adjwgt, nparts, assignment, comm);CHKERRQ(ierr);
2141137cd93aSLisandro Dalcin       }
2142137cd93aSLisandro Dalcin     }
2143137cd93aSLisandro Dalcin     ierr = PetscFree(vwgt);CHKERRQ(ierr);
2144137cd93aSLisandro Dalcin   }
2145137cd93aSLisandro Dalcin 
2146137cd93aSLisandro Dalcin   /* Convert to PetscSection+IS */
2147137cd93aSLisandro Dalcin   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
2148137cd93aSLisandro Dalcin   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
2149137cd93aSLisandro Dalcin   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
2150137cd93aSLisandro Dalcin   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
2151137cd93aSLisandro Dalcin   for (p = 0, i = 0; p < nparts; ++p) {
2152137cd93aSLisandro Dalcin     for (v = 0; v < nvtxs; ++v) {
2153137cd93aSLisandro Dalcin       if (assignment[v] == p) points[i++] = v;
2154137cd93aSLisandro Dalcin     }
2155137cd93aSLisandro Dalcin   }
2156137cd93aSLisandro Dalcin   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2157137cd93aSLisandro Dalcin   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2158137cd93aSLisandro Dalcin 
2159137cd93aSLisandro Dalcin   ierr = PetscFree2(vtxdist,assignment);CHKERRQ(ierr);
2160137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2161137cd93aSLisandro Dalcin #else
2162137cd93aSLisandro Dalcin   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-ptscotch.");
2163137cd93aSLisandro Dalcin #endif
2164137cd93aSLisandro Dalcin }
2165137cd93aSLisandro Dalcin 
2166137cd93aSLisandro Dalcin static PetscErrorCode PetscPartitionerInitialize_PTScotch(PetscPartitioner part)
2167137cd93aSLisandro Dalcin {
2168137cd93aSLisandro Dalcin   PetscFunctionBegin;
2169074d466cSStefano Zampini   part->noGraph             = PETSC_FALSE;
2170137cd93aSLisandro Dalcin   part->ops->view           = PetscPartitionerView_PTScotch;
2171137cd93aSLisandro Dalcin   part->ops->destroy        = PetscPartitionerDestroy_PTScotch;
2172137cd93aSLisandro Dalcin   part->ops->partition      = PetscPartitionerPartition_PTScotch;
2173137cd93aSLisandro Dalcin   part->ops->setfromoptions = PetscPartitionerSetFromOptions_PTScotch;
2174137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2175137cd93aSLisandro Dalcin }
2176137cd93aSLisandro Dalcin 
2177137cd93aSLisandro Dalcin /*MC
2178137cd93aSLisandro Dalcin   PETSCPARTITIONERPTSCOTCH = "ptscotch" - A PetscPartitioner object using the PT-Scotch library
2179137cd93aSLisandro Dalcin 
2180137cd93aSLisandro Dalcin   Level: intermediate
2181137cd93aSLisandro Dalcin 
2182137cd93aSLisandro Dalcin .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
2183137cd93aSLisandro Dalcin M*/
2184137cd93aSLisandro Dalcin 
2185137cd93aSLisandro Dalcin PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_PTScotch(PetscPartitioner part)
2186137cd93aSLisandro Dalcin {
2187137cd93aSLisandro Dalcin   PetscPartitioner_PTScotch *p;
2188137cd93aSLisandro Dalcin   PetscErrorCode          ierr;
2189137cd93aSLisandro Dalcin 
2190137cd93aSLisandro Dalcin   PetscFunctionBegin;
2191137cd93aSLisandro Dalcin   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
2192137cd93aSLisandro Dalcin   ierr = PetscNewLog(part, &p);CHKERRQ(ierr);
2193137cd93aSLisandro Dalcin   part->data = p;
2194137cd93aSLisandro Dalcin 
2195137cd93aSLisandro Dalcin   p->strategy  = 0;
2196137cd93aSLisandro Dalcin   p->imbalance = 0.01;
2197137cd93aSLisandro Dalcin 
2198137cd93aSLisandro Dalcin   ierr = PetscPartitionerInitialize_PTScotch(part);CHKERRQ(ierr);
2199137cd93aSLisandro Dalcin   ierr = PetscCitationsRegister(PTScotchPartitionerCitation, &PTScotchPartitionercite);CHKERRQ(ierr);
2200137cd93aSLisandro Dalcin   PetscFunctionReturn(0);
2201137cd93aSLisandro Dalcin }
2202137cd93aSLisandro Dalcin 
2203137cd93aSLisandro Dalcin 
22045680f57bSMatthew G. Knepley /*@
22055680f57bSMatthew G. Knepley   DMPlexGetPartitioner - Get the mesh partitioner
22065680f57bSMatthew G. Knepley 
22075680f57bSMatthew G. Knepley   Not collective
22085680f57bSMatthew G. Knepley 
22095680f57bSMatthew G. Knepley   Input Parameter:
22105680f57bSMatthew G. Knepley . dm - The DM
22115680f57bSMatthew G. Knepley 
22125680f57bSMatthew G. Knepley   Output Parameter:
22135680f57bSMatthew G. Knepley . part - The PetscPartitioner
22145680f57bSMatthew G. Knepley 
22155680f57bSMatthew G. Knepley   Level: developer
22165680f57bSMatthew G. Knepley 
221798599a47SLawrence Mitchell   Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner.
221898599a47SLawrence Mitchell 
221998599a47SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerCreate()
22205680f57bSMatthew G. Knepley @*/
22215680f57bSMatthew G. Knepley PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part)
22225680f57bSMatthew G. Knepley {
22235680f57bSMatthew G. Knepley   DM_Plex       *mesh = (DM_Plex *) dm->data;
22245680f57bSMatthew G. Knepley 
22255680f57bSMatthew G. Knepley   PetscFunctionBegin;
22265680f57bSMatthew G. Knepley   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
22275680f57bSMatthew G. Knepley   PetscValidPointer(part, 2);
22285680f57bSMatthew G. Knepley   *part = mesh->partitioner;
22295680f57bSMatthew G. Knepley   PetscFunctionReturn(0);
22305680f57bSMatthew G. Knepley }
22315680f57bSMatthew G. Knepley 
223271bb2955SLawrence Mitchell /*@
223371bb2955SLawrence Mitchell   DMPlexSetPartitioner - Set the mesh partitioner
223471bb2955SLawrence Mitchell 
2235fe2efc57SMark   logically collective on DM
223671bb2955SLawrence Mitchell 
223771bb2955SLawrence Mitchell   Input Parameters:
223871bb2955SLawrence Mitchell + dm - The DM
223971bb2955SLawrence Mitchell - part - The partitioner
224071bb2955SLawrence Mitchell 
224171bb2955SLawrence Mitchell   Level: developer
224271bb2955SLawrence Mitchell 
224371bb2955SLawrence Mitchell   Note: Any existing PetscPartitioner will be destroyed.
224471bb2955SLawrence Mitchell 
224571bb2955SLawrence Mitchell .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate()
224671bb2955SLawrence Mitchell @*/
224771bb2955SLawrence Mitchell PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part)
224871bb2955SLawrence Mitchell {
224971bb2955SLawrence Mitchell   DM_Plex       *mesh = (DM_Plex *) dm->data;
225071bb2955SLawrence Mitchell   PetscErrorCode ierr;
225171bb2955SLawrence Mitchell 
225271bb2955SLawrence Mitchell   PetscFunctionBegin;
225371bb2955SLawrence Mitchell   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
225471bb2955SLawrence Mitchell   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2);
225571bb2955SLawrence Mitchell   ierr = PetscObjectReference((PetscObject)part);CHKERRQ(ierr);
225671bb2955SLawrence Mitchell   ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr);
225771bb2955SLawrence Mitchell   mesh->partitioner = part;
225871bb2955SLawrence Mitchell   PetscFunctionReturn(0);
225971bb2955SLawrence Mitchell }
226071bb2955SLawrence Mitchell 
22618e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosure_Private(DM dm, PetscHSetI ht, PetscInt point)
22628e330a33SStefano Zampini {
22638e330a33SStefano Zampini   const PetscInt *cone;
22648e330a33SStefano Zampini   PetscInt       coneSize, c;
22658e330a33SStefano Zampini   PetscBool      missing;
22668e330a33SStefano Zampini   PetscErrorCode ierr;
22678e330a33SStefano Zampini 
22688e330a33SStefano Zampini   PetscFunctionBeginHot;
22698e330a33SStefano Zampini   ierr = PetscHSetIQueryAdd(ht, point, &missing);CHKERRQ(ierr);
22708e330a33SStefano Zampini   if (missing) {
22718e330a33SStefano Zampini     ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
22728e330a33SStefano Zampini     ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
22738e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
22748e330a33SStefano Zampini       ierr = DMPlexAddClosure_Private(dm, ht, cone[c]);CHKERRQ(ierr);
22758e330a33SStefano Zampini     }
22768e330a33SStefano Zampini   }
22778e330a33SStefano Zampini   PetscFunctionReturn(0);
22788e330a33SStefano Zampini }
22798e330a33SStefano Zampini 
22808e330a33SStefano Zampini PETSC_UNUSED static PetscErrorCode DMPlexAddClosure_Tree(DM dm, PetscHSetI ht, PetscInt point, PetscBool up, PetscBool down)
2281270bba0cSToby Isaac {
2282270bba0cSToby Isaac   PetscErrorCode ierr;
2283270bba0cSToby Isaac 
2284270bba0cSToby Isaac   PetscFunctionBegin;
22856a5a2ffdSToby Isaac   if (up) {
22866a5a2ffdSToby Isaac     PetscInt parent;
22876a5a2ffdSToby Isaac 
2288270bba0cSToby Isaac     ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
22896a5a2ffdSToby Isaac     if (parent != point) {
22906a5a2ffdSToby Isaac       PetscInt closureSize, *closure = NULL, i;
22916a5a2ffdSToby Isaac 
2292270bba0cSToby Isaac       ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2293270bba0cSToby Isaac       for (i = 0; i < closureSize; i++) {
2294270bba0cSToby Isaac         PetscInt cpoint = closure[2*i];
2295270bba0cSToby Isaac 
2296e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
22971b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr);
2298270bba0cSToby Isaac       }
2299270bba0cSToby Isaac       ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
23006a5a2ffdSToby Isaac     }
23016a5a2ffdSToby Isaac   }
23026a5a2ffdSToby Isaac   if (down) {
23036a5a2ffdSToby Isaac     PetscInt numChildren;
23046a5a2ffdSToby Isaac     const PetscInt *children;
23056a5a2ffdSToby Isaac 
23066a5a2ffdSToby Isaac     ierr = DMPlexGetTreeChildren(dm,point,&numChildren,&children);CHKERRQ(ierr);
23076a5a2ffdSToby Isaac     if (numChildren) {
23086a5a2ffdSToby Isaac       PetscInt i;
23096a5a2ffdSToby Isaac 
23106a5a2ffdSToby Isaac       for (i = 0; i < numChildren; i++) {
23116a5a2ffdSToby Isaac         PetscInt cpoint = children[i];
23126a5a2ffdSToby Isaac 
2313e8f14785SLisandro Dalcin         ierr = PetscHSetIAdd(ht, cpoint);CHKERRQ(ierr);
23141b807c88SLisandro Dalcin         ierr = DMPlexAddClosure_Tree(dm,ht,cpoint,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr);
23156a5a2ffdSToby Isaac       }
23166a5a2ffdSToby Isaac     }
23176a5a2ffdSToby Isaac   }
2318270bba0cSToby Isaac   PetscFunctionReturn(0);
2319270bba0cSToby Isaac }
2320270bba0cSToby Isaac 
23218e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Up_Private(DM dm, PetscHSetI ht, PetscInt point)
23228e330a33SStefano Zampini {
23238e330a33SStefano Zampini   PetscInt       parent;
23248e330a33SStefano Zampini   PetscErrorCode ierr;
2325825f8a23SLisandro Dalcin 
23268e330a33SStefano Zampini   PetscFunctionBeginHot;
23278e330a33SStefano Zampini   ierr = DMPlexGetTreeParent(dm, point, &parent,NULL);CHKERRQ(ierr);
23288e330a33SStefano Zampini   if (point != parent) {
23298e330a33SStefano Zampini     const PetscInt *cone;
23308e330a33SStefano Zampini     PetscInt       coneSize, c;
23318e330a33SStefano Zampini 
23328e330a33SStefano Zampini     ierr = DMPlexAddClosureTree_Up_Private(dm, ht, parent);CHKERRQ(ierr);
23338e330a33SStefano Zampini     ierr = DMPlexAddClosure_Private(dm, ht, parent);CHKERRQ(ierr);
23348e330a33SStefano Zampini     ierr = DMPlexGetCone(dm, parent, &cone);CHKERRQ(ierr);
23358e330a33SStefano Zampini     ierr = DMPlexGetConeSize(dm, parent, &coneSize);CHKERRQ(ierr);
23368e330a33SStefano Zampini     for (c = 0; c < coneSize; c++) {
23378e330a33SStefano Zampini       const PetscInt cp = cone[c];
23388e330a33SStefano Zampini 
23398e330a33SStefano Zampini       ierr = DMPlexAddClosureTree_Up_Private(dm, ht, cp);CHKERRQ(ierr);
23408e330a33SStefano Zampini     }
23418e330a33SStefano Zampini   }
23428e330a33SStefano Zampini   PetscFunctionReturn(0);
23438e330a33SStefano Zampini }
23448e330a33SStefano Zampini 
23458e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Down_Private(DM dm, PetscHSetI ht, PetscInt point)
23468e330a33SStefano Zampini {
23478e330a33SStefano Zampini   PetscInt       i, numChildren;
23488e330a33SStefano Zampini   const PetscInt *children;
23498e330a33SStefano Zampini   PetscErrorCode ierr;
23508e330a33SStefano Zampini 
23518e330a33SStefano Zampini   PetscFunctionBeginHot;
23528e330a33SStefano Zampini   ierr = DMPlexGetTreeChildren(dm, point, &numChildren, &children);CHKERRQ(ierr);
23538e330a33SStefano Zampini   for (i = 0; i < numChildren; i++) {
23548e330a33SStefano Zampini     ierr = PetscHSetIAdd(ht, children[i]);CHKERRQ(ierr);
23558e330a33SStefano Zampini   }
23568e330a33SStefano Zampini   PetscFunctionReturn(0);
23578e330a33SStefano Zampini }
23588e330a33SStefano Zampini 
23598e330a33SStefano Zampini static PetscErrorCode DMPlexAddClosureTree_Private(DM dm, PetscHSetI ht, PetscInt point)
23608e330a33SStefano Zampini {
23618e330a33SStefano Zampini   const PetscInt *cone;
23628e330a33SStefano Zampini   PetscInt       coneSize, c;
23638e330a33SStefano Zampini   PetscErrorCode ierr;
23648e330a33SStefano Zampini 
23658e330a33SStefano Zampini   PetscFunctionBeginHot;
23668e330a33SStefano Zampini   ierr = PetscHSetIAdd(ht, point);CHKERRQ(ierr);
23678e330a33SStefano Zampini   ierr = DMPlexAddClosureTree_Up_Private(dm, ht, point);CHKERRQ(ierr);
23688e330a33SStefano Zampini   ierr = DMPlexAddClosureTree_Down_Private(dm, ht, point);CHKERRQ(ierr);
23698e330a33SStefano Zampini   ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
23708e330a33SStefano Zampini   ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
23718e330a33SStefano Zampini   for (c = 0; c < coneSize; c++) {
23728e330a33SStefano Zampini     ierr = DMPlexAddClosureTree_Private(dm, ht, cone[c]);CHKERRQ(ierr);
23738e330a33SStefano Zampini   }
23748e330a33SStefano Zampini   PetscFunctionReturn(0);
23758e330a33SStefano Zampini }
23768e330a33SStefano Zampini 
23778e330a33SStefano Zampini PetscErrorCode DMPlexClosurePoints_Private(DM dm, PetscInt numPoints, const PetscInt points[], IS *closureIS)
2378825f8a23SLisandro Dalcin {
2379825f8a23SLisandro Dalcin   DM_Plex         *mesh = (DM_Plex *)dm->data;
23808e330a33SStefano Zampini   const PetscBool hasTree = (mesh->parentSection || mesh->childSection) ? PETSC_TRUE : PETSC_FALSE;
23818e330a33SStefano Zampini   PetscInt        nelems, *elems, off = 0, p;
2382825f8a23SLisandro Dalcin   PetscHSetI      ht;
2383825f8a23SLisandro Dalcin   PetscErrorCode  ierr;
2384825f8a23SLisandro Dalcin 
2385825f8a23SLisandro Dalcin   PetscFunctionBegin;
2386825f8a23SLisandro Dalcin   ierr = PetscHSetICreate(&ht);CHKERRQ(ierr);
2387825f8a23SLisandro Dalcin   ierr = PetscHSetIResize(ht, numPoints*16);CHKERRQ(ierr);
23888e330a33SStefano Zampini   if (!hasTree) {
23898e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
23908e330a33SStefano Zampini       ierr = DMPlexAddClosure_Private(dm, ht, points[p]);CHKERRQ(ierr);
23918e330a33SStefano Zampini     }
23928e330a33SStefano Zampini   } else {
23938e330a33SStefano Zampini #if 1
23948e330a33SStefano Zampini     for (p = 0; p < numPoints; ++p) {
23958e330a33SStefano Zampini       ierr = DMPlexAddClosureTree_Private(dm, ht, points[p]);CHKERRQ(ierr);
23968e330a33SStefano Zampini     }
23978e330a33SStefano Zampini #else
23988e330a33SStefano Zampini     PetscInt  *closure = NULL, closureSize, c;
2399825f8a23SLisandro Dalcin     for (p = 0; p < numPoints; ++p) {
2400825f8a23SLisandro Dalcin       ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2401825f8a23SLisandro Dalcin       for (c = 0; c < closureSize*2; c += 2) {
2402825f8a23SLisandro Dalcin         ierr = PetscHSetIAdd(ht, closure[c]);CHKERRQ(ierr);
2403825f8a23SLisandro Dalcin         if (hasTree) {ierr = DMPlexAddClosure_Tree(dm, ht, closure[c], PETSC_TRUE, PETSC_TRUE);CHKERRQ(ierr);}
2404825f8a23SLisandro Dalcin       }
2405825f8a23SLisandro Dalcin     }
2406825f8a23SLisandro Dalcin     if (closure) {ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, NULL, &closure);CHKERRQ(ierr);}
24078e330a33SStefano Zampini #endif
24088e330a33SStefano Zampini   }
2409825f8a23SLisandro Dalcin   ierr = PetscHSetIGetSize(ht, &nelems);CHKERRQ(ierr);
2410825f8a23SLisandro Dalcin   ierr = PetscMalloc1(nelems, &elems);CHKERRQ(ierr);
2411825f8a23SLisandro Dalcin   ierr = PetscHSetIGetElems(ht, &off, elems);CHKERRQ(ierr);
2412825f8a23SLisandro Dalcin   ierr = PetscHSetIDestroy(&ht);CHKERRQ(ierr);
2413825f8a23SLisandro Dalcin   ierr = PetscSortInt(nelems, elems);CHKERRQ(ierr);
2414825f8a23SLisandro Dalcin   ierr = ISCreateGeneral(PETSC_COMM_SELF, nelems, elems, PETSC_OWN_POINTER, closureIS);CHKERRQ(ierr);
2415825f8a23SLisandro Dalcin   PetscFunctionReturn(0);
2416825f8a23SLisandro Dalcin }
2417825f8a23SLisandro Dalcin 
24185abbe4feSMichael Lange /*@
24195abbe4feSMichael Lange   DMPlexPartitionLabelClosure - Add the closure of all points to the partition label
24205abbe4feSMichael Lange 
24215abbe4feSMichael Lange   Input Parameters:
24225abbe4feSMichael Lange + dm     - The DM
24235abbe4feSMichael Lange - label  - DMLabel assinging ranks to remote roots
24245abbe4feSMichael Lange 
24255abbe4feSMichael Lange   Level: developer
24265abbe4feSMichael Lange 
242730b0ce1bSStefano Zampini .seealso: DMPlexPartitionLabelCreateSF(), DMPlexDistribute(), DMPlexCreateOverlap()
24285abbe4feSMichael Lange @*/
24295abbe4feSMichael Lange PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label)
24309ffc88e4SToby Isaac {
2431825f8a23SLisandro Dalcin   IS              rankIS,   pointIS, closureIS;
24325abbe4feSMichael Lange   const PetscInt *ranks,   *points;
2433825f8a23SLisandro Dalcin   PetscInt        numRanks, numPoints, r;
24349ffc88e4SToby Isaac   PetscErrorCode  ierr;
24359ffc88e4SToby Isaac 
24369ffc88e4SToby Isaac   PetscFunctionBegin;
24375abbe4feSMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
24385abbe4feSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
24395abbe4feSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
24405abbe4feSMichael Lange   for (r = 0; r < numRanks; ++r) {
24415abbe4feSMichael Lange     const PetscInt rank = ranks[r];
24425abbe4feSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
24435abbe4feSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
24445abbe4feSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
24458e330a33SStefano Zampini     ierr = DMPlexClosurePoints_Private(dm, numPoints, points, &closureIS);CHKERRQ(ierr);
24465abbe4feSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
24475abbe4feSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2448825f8a23SLisandro Dalcin     ierr = DMLabelSetStratumIS(label, rank, closureIS);CHKERRQ(ierr);
2449825f8a23SLisandro Dalcin     ierr = ISDestroy(&closureIS);CHKERRQ(ierr);
24509ffc88e4SToby Isaac   }
24515abbe4feSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
24525abbe4feSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
24539ffc88e4SToby Isaac   PetscFunctionReturn(0);
24549ffc88e4SToby Isaac }
24559ffc88e4SToby Isaac 
245624d039d7SMichael Lange /*@
245724d039d7SMichael Lange   DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label
245824d039d7SMichael Lange 
245924d039d7SMichael Lange   Input Parameters:
246024d039d7SMichael Lange + dm     - The DM
246124d039d7SMichael Lange - label  - DMLabel assinging ranks to remote roots
246224d039d7SMichael Lange 
246324d039d7SMichael Lange   Level: developer
246424d039d7SMichael Lange 
246524d039d7SMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
246624d039d7SMichael Lange @*/
246724d039d7SMichael Lange PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label)
246870034214SMatthew G. Knepley {
246924d039d7SMichael Lange   IS              rankIS,   pointIS;
247024d039d7SMichael Lange   const PetscInt *ranks,   *points;
247124d039d7SMichael Lange   PetscInt        numRanks, numPoints, r, p, a, adjSize;
247224d039d7SMichael Lange   PetscInt       *adj = NULL;
247370034214SMatthew G. Knepley   PetscErrorCode  ierr;
247470034214SMatthew G. Knepley 
247570034214SMatthew G. Knepley   PetscFunctionBegin;
247624d039d7SMichael Lange   ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr);
247724d039d7SMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
247824d039d7SMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
247924d039d7SMichael Lange   for (r = 0; r < numRanks; ++r) {
248024d039d7SMichael Lange     const PetscInt rank = ranks[r];
248170034214SMatthew G. Knepley 
248224d039d7SMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr);
248324d039d7SMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
248424d039d7SMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
248570034214SMatthew G. Knepley     for (p = 0; p < numPoints; ++p) {
248624d039d7SMichael Lange       adjSize = PETSC_DETERMINE;
248724d039d7SMichael Lange       ierr = DMPlexGetAdjacency(dm, points[p], &adjSize, &adj);CHKERRQ(ierr);
248824d039d7SMichael Lange       for (a = 0; a < adjSize; ++a) {ierr = DMLabelSetValue(label, adj[a], rank);CHKERRQ(ierr);}
248970034214SMatthew G. Knepley     }
249024d039d7SMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
249124d039d7SMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
249270034214SMatthew G. Knepley   }
249324d039d7SMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
249424d039d7SMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
249524d039d7SMichael Lange   ierr = PetscFree(adj);CHKERRQ(ierr);
249624d039d7SMichael Lange   PetscFunctionReturn(0);
249770034214SMatthew G. Knepley }
249870034214SMatthew G. Knepley 
2499be200f8dSMichael Lange /*@
2500be200f8dSMichael Lange   DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF
2501be200f8dSMichael Lange 
2502be200f8dSMichael Lange   Input Parameters:
2503be200f8dSMichael Lange + dm     - The DM
2504be200f8dSMichael Lange - label  - DMLabel assinging ranks to remote roots
2505be200f8dSMichael Lange 
2506be200f8dSMichael Lange   Level: developer
2507be200f8dSMichael Lange 
2508be200f8dSMichael Lange   Note: This is required when generating multi-level overlaps to capture
2509be200f8dSMichael Lange   overlap points from non-neighbouring partitions.
2510be200f8dSMichael Lange 
2511be200f8dSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
2512be200f8dSMichael Lange @*/
2513be200f8dSMichael Lange PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label)
2514be200f8dSMichael Lange {
2515be200f8dSMichael Lange   MPI_Comm        comm;
2516be200f8dSMichael Lange   PetscMPIInt     rank;
2517be200f8dSMichael Lange   PetscSF         sfPoint;
25185d04f6ebSMichael Lange   DMLabel         lblRoots, lblLeaves;
2519be200f8dSMichael Lange   IS              rankIS, pointIS;
2520be200f8dSMichael Lange   const PetscInt *ranks;
2521be200f8dSMichael Lange   PetscInt        numRanks, r;
2522be200f8dSMichael Lange   PetscErrorCode  ierr;
2523be200f8dSMichael Lange 
2524be200f8dSMichael Lange   PetscFunctionBegin;
2525be200f8dSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
2526be200f8dSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2527be200f8dSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
25285d04f6ebSMichael Lange   /* Pull point contributions from remote leaves into local roots */
25295d04f6ebSMichael Lange   ierr = DMLabelGather(label, sfPoint, &lblLeaves);CHKERRQ(ierr);
25305d04f6ebSMichael Lange   ierr = DMLabelGetValueIS(lblLeaves, &rankIS);CHKERRQ(ierr);
25315d04f6ebSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
25325d04f6ebSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
25335d04f6ebSMichael Lange   for (r = 0; r < numRanks; ++r) {
25345d04f6ebSMichael Lange     const PetscInt remoteRank = ranks[r];
25355d04f6ebSMichael Lange     if (remoteRank == rank) continue;
25365d04f6ebSMichael Lange     ierr = DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS);CHKERRQ(ierr);
25375d04f6ebSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
25385d04f6ebSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
25395d04f6ebSMichael Lange   }
25405d04f6ebSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
25415d04f6ebSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
25425d04f6ebSMichael Lange   ierr = DMLabelDestroy(&lblLeaves);CHKERRQ(ierr);
2543be200f8dSMichael Lange   /* Push point contributions from roots into remote leaves */
2544be200f8dSMichael Lange   ierr = DMLabelDistribute(label, sfPoint, &lblRoots);CHKERRQ(ierr);
2545be200f8dSMichael Lange   ierr = DMLabelGetValueIS(lblRoots, &rankIS);CHKERRQ(ierr);
2546be200f8dSMichael Lange   ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr);
2547be200f8dSMichael Lange   ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr);
2548be200f8dSMichael Lange   for (r = 0; r < numRanks; ++r) {
2549be200f8dSMichael Lange     const PetscInt remoteRank = ranks[r];
2550be200f8dSMichael Lange     if (remoteRank == rank) continue;
2551be200f8dSMichael Lange     ierr = DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS);CHKERRQ(ierr);
2552be200f8dSMichael Lange     ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr);
2553be200f8dSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
2554be200f8dSMichael Lange   }
2555be200f8dSMichael Lange   ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr);
2556be200f8dSMichael Lange   ierr = ISDestroy(&rankIS);CHKERRQ(ierr);
2557be200f8dSMichael Lange   ierr = DMLabelDestroy(&lblRoots);CHKERRQ(ierr);
2558be200f8dSMichael Lange   PetscFunctionReturn(0);
2559be200f8dSMichael Lange }
2560be200f8dSMichael Lange 
25611fd9873aSMichael Lange /*@
25621fd9873aSMichael Lange   DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label
25631fd9873aSMichael Lange 
25641fd9873aSMichael Lange   Input Parameters:
25651fd9873aSMichael Lange + dm        - The DM
25661fd9873aSMichael Lange . rootLabel - DMLabel assinging ranks to local roots
2567fe2efc57SMark - processSF - A star forest mapping into the local index on each remote rank
25681fd9873aSMichael Lange 
25691fd9873aSMichael Lange   Output Parameter:
2570fe2efc57SMark . leafLabel - DMLabel assinging ranks to remote roots
25711fd9873aSMichael Lange 
25721fd9873aSMichael Lange   Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The
25731fd9873aSMichael Lange   resulting leafLabel is a receiver mapping of remote roots to their parent rank.
25741fd9873aSMichael Lange 
25751fd9873aSMichael Lange   Level: developer
25761fd9873aSMichael Lange 
25771fd9873aSMichael Lange .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap
25781fd9873aSMichael Lange @*/
25791fd9873aSMichael Lange PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel)
25801fd9873aSMichael Lange {
25811fd9873aSMichael Lange   MPI_Comm           comm;
2582874ddda9SLisandro Dalcin   PetscMPIInt        rank, size, r;
2583874ddda9SLisandro Dalcin   PetscInt           p, n, numNeighbors, numPoints, dof, off, rootSize, l, nleaves, leafSize;
25841fd9873aSMichael Lange   PetscSF            sfPoint;
2585874ddda9SLisandro Dalcin   PetscSection       rootSection;
25861fd9873aSMichael Lange   PetscSFNode       *rootPoints, *leafPoints;
25871fd9873aSMichael Lange   const PetscSFNode *remote;
25881fd9873aSMichael Lange   const PetscInt    *local, *neighbors;
25891fd9873aSMichael Lange   IS                 valueIS;
2590874ddda9SLisandro Dalcin   PetscBool          mpiOverflow = PETSC_FALSE;
25911fd9873aSMichael Lange   PetscErrorCode     ierr;
25921fd9873aSMichael Lange 
25931fd9873aSMichael Lange   PetscFunctionBegin;
259430b0ce1bSStefano Zampini   ierr = PetscLogEventBegin(DMPLEX_PartLabelInvert,dm,0,0,0);CHKERRQ(ierr);
25951fd9873aSMichael Lange   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
25961fd9873aSMichael Lange   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
25979852e123SBarry Smith   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
25981fd9873aSMichael Lange   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
25991fd9873aSMichael Lange 
26001fd9873aSMichael Lange   /* Convert to (point, rank) and use actual owners */
26011fd9873aSMichael Lange   ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr);
26029852e123SBarry Smith   ierr = PetscSectionSetChart(rootSection, 0, size);CHKERRQ(ierr);
26031fd9873aSMichael Lange   ierr = DMLabelGetValueIS(rootLabel, &valueIS);CHKERRQ(ierr);
26041fd9873aSMichael Lange   ierr = ISGetLocalSize(valueIS, &numNeighbors);CHKERRQ(ierr);
26051fd9873aSMichael Lange   ierr = ISGetIndices(valueIS, &neighbors);CHKERRQ(ierr);
26061fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
26071fd9873aSMichael Lange     ierr = DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints);CHKERRQ(ierr);
26081fd9873aSMichael Lange     ierr = PetscSectionAddDof(rootSection, neighbors[n], numPoints);CHKERRQ(ierr);
26091fd9873aSMichael Lange   }
26101fd9873aSMichael Lange   ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
2611874ddda9SLisandro Dalcin   ierr = PetscSectionGetStorageSize(rootSection, &rootSize);CHKERRQ(ierr);
2612874ddda9SLisandro Dalcin   ierr = PetscMalloc1(rootSize, &rootPoints);CHKERRQ(ierr);
26131fd9873aSMichael Lange   ierr = PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote);CHKERRQ(ierr);
26141fd9873aSMichael Lange   for (n = 0; n < numNeighbors; ++n) {
26151fd9873aSMichael Lange     IS              pointIS;
26161fd9873aSMichael Lange     const PetscInt *points;
26171fd9873aSMichael Lange 
26181fd9873aSMichael Lange     ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
26191fd9873aSMichael Lange     ierr = DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS);CHKERRQ(ierr);
26201fd9873aSMichael Lange     ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
26211fd9873aSMichael Lange     ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
26221fd9873aSMichael Lange     for (p = 0; p < numPoints; ++p) {
2623f8987ae8SMichael Lange       if (local) {ierr = PetscFindInt(points[p], nleaves, local, &l);CHKERRQ(ierr);}
2624f8987ae8SMichael Lange       else       {l = -1;}
26251fd9873aSMichael Lange       if (l >= 0) {rootPoints[off+p] = remote[l];}
26261fd9873aSMichael Lange       else        {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;}
26271fd9873aSMichael Lange     }
26281fd9873aSMichael Lange     ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
26291fd9873aSMichael Lange     ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
26301fd9873aSMichael Lange   }
2631874ddda9SLisandro Dalcin 
2632874ddda9SLisandro Dalcin   /* Try to communicate overlap using All-to-All */
2633874ddda9SLisandro Dalcin   if (!processSF) {
2634874ddda9SLisandro Dalcin     PetscInt64  counter = 0;
2635874ddda9SLisandro Dalcin     PetscBool   locOverflow = PETSC_FALSE;
2636874ddda9SLisandro Dalcin     PetscMPIInt *scounts, *sdispls, *rcounts, *rdispls;
2637874ddda9SLisandro Dalcin 
2638874ddda9SLisandro Dalcin     ierr = PetscCalloc4(size, &scounts, size, &sdispls, size, &rcounts, size, &rdispls);CHKERRQ(ierr);
2639874ddda9SLisandro Dalcin     for (n = 0; n < numNeighbors; ++n) {
2640874ddda9SLisandro Dalcin       ierr = PetscSectionGetDof(rootSection, neighbors[n], &dof);CHKERRQ(ierr);
2641874ddda9SLisandro Dalcin       ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr);
2642874ddda9SLisandro Dalcin #if defined(PETSC_USE_64BIT_INDICES)
2643874ddda9SLisandro Dalcin       if (dof > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2644874ddda9SLisandro Dalcin       if (off > PETSC_MPI_INT_MAX) {locOverflow = PETSC_TRUE; break;}
2645874ddda9SLisandro Dalcin #endif
2646874ddda9SLisandro Dalcin       scounts[neighbors[n]] = (PetscMPIInt) dof;
2647874ddda9SLisandro Dalcin       sdispls[neighbors[n]] = (PetscMPIInt) off;
2648874ddda9SLisandro Dalcin     }
2649874ddda9SLisandro Dalcin     ierr = MPI_Alltoall(scounts, 1, MPI_INT, rcounts, 1, MPI_INT, comm);CHKERRQ(ierr);
2650874ddda9SLisandro Dalcin     for (r = 0; r < size; ++r) { rdispls[r] = (int)counter; counter += rcounts[r]; }
2651874ddda9SLisandro Dalcin     if (counter > PETSC_MPI_INT_MAX) locOverflow = PETSC_TRUE;
2652874ddda9SLisandro Dalcin     ierr = MPI_Allreduce(&locOverflow, &mpiOverflow, 1, MPIU_BOOL, MPI_LOR, comm);CHKERRQ(ierr);
2653874ddda9SLisandro Dalcin     if (!mpiOverflow) {
265494b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using Alltoallv for mesh distribution\n");CHKERRQ(ierr);
2655874ddda9SLisandro Dalcin       leafSize = (PetscInt) counter;
2656874ddda9SLisandro Dalcin       ierr = PetscMalloc1(leafSize, &leafPoints);CHKERRQ(ierr);
2657874ddda9SLisandro Dalcin       ierr = MPI_Alltoallv(rootPoints, scounts, sdispls, MPIU_2INT, leafPoints, rcounts, rdispls, MPIU_2INT, comm);CHKERRQ(ierr);
2658874ddda9SLisandro Dalcin     }
2659874ddda9SLisandro Dalcin     ierr = PetscFree4(scounts, sdispls, rcounts, rdispls);CHKERRQ(ierr);
2660874ddda9SLisandro Dalcin   }
2661874ddda9SLisandro Dalcin 
2662874ddda9SLisandro Dalcin   /* Communicate overlap using process star forest */
2663874ddda9SLisandro Dalcin   if (processSF || mpiOverflow) {
2664874ddda9SLisandro Dalcin     PetscSF      procSF;
2665874ddda9SLisandro Dalcin     PetscSection leafSection;
2666874ddda9SLisandro Dalcin 
2667874ddda9SLisandro Dalcin     if (processSF) {
266894b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using processSF for mesh distribution\n");CHKERRQ(ierr);
2669874ddda9SLisandro Dalcin       ierr = PetscObjectReference((PetscObject)processSF);CHKERRQ(ierr);
2670874ddda9SLisandro Dalcin       procSF = processSF;
2671874ddda9SLisandro Dalcin     } else {
267294b10faeSStefano Zampini       ierr = PetscInfo(dm,"Using processSF for mesh distribution (MPI overflow)\n");CHKERRQ(ierr);
2673874ddda9SLisandro Dalcin       ierr = PetscSFCreate(comm,&procSF);CHKERRQ(ierr);
2674900e0f05SJunchao Zhang       ierr = PetscSFSetGraphWithPattern(procSF,NULL,PETSCSF_PATTERN_ALLTOALL);CHKERRQ(ierr);
2675874ddda9SLisandro Dalcin     }
2676874ddda9SLisandro Dalcin 
2677874ddda9SLisandro Dalcin     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &leafSection);CHKERRQ(ierr);
2678900e0f05SJunchao Zhang     ierr = DMPlexDistributeData(dm, procSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints);CHKERRQ(ierr);
2679874ddda9SLisandro Dalcin     ierr = PetscSectionGetStorageSize(leafSection, &leafSize);CHKERRQ(ierr);
2680874ddda9SLisandro Dalcin     ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
2681874ddda9SLisandro Dalcin     ierr = PetscSFDestroy(&procSF);CHKERRQ(ierr);
2682874ddda9SLisandro Dalcin   }
2683874ddda9SLisandro Dalcin 
2684874ddda9SLisandro Dalcin   for (p = 0; p < leafSize; p++) {
26851fd9873aSMichael Lange     ierr = DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank);CHKERRQ(ierr);
26861fd9873aSMichael Lange   }
2687874ddda9SLisandro Dalcin 
2688874ddda9SLisandro Dalcin   ierr = ISRestoreIndices(valueIS, &neighbors);CHKERRQ(ierr);
2689874ddda9SLisandro Dalcin   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
26901fd9873aSMichael Lange   ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
2691874ddda9SLisandro Dalcin   ierr = PetscFree(rootPoints);CHKERRQ(ierr);
26921fd9873aSMichael Lange   ierr = PetscFree(leafPoints);CHKERRQ(ierr);
269330b0ce1bSStefano Zampini   ierr = PetscLogEventEnd(DMPLEX_PartLabelInvert,dm,0,0,0);CHKERRQ(ierr);
26941fd9873aSMichael Lange   PetscFunctionReturn(0);
26951fd9873aSMichael Lange }
26961fd9873aSMichael Lange 
2697aa3148a8SMichael Lange /*@
2698aa3148a8SMichael Lange   DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points
2699aa3148a8SMichael Lange 
2700aa3148a8SMichael Lange   Input Parameters:
2701aa3148a8SMichael Lange + dm    - The DM
2702aa3148a8SMichael Lange . label - DMLabel assinging ranks to remote roots
2703aa3148a8SMichael Lange 
2704aa3148a8SMichael Lange   Output Parameter:
2705fe2efc57SMark . sf    - The star forest communication context encapsulating the defined mapping
2706aa3148a8SMichael Lange 
2707aa3148a8SMichael Lange   Note: The incoming label is a receiver mapping of remote points to their parent rank.
2708aa3148a8SMichael Lange 
2709aa3148a8SMichael Lange   Level: developer
2710aa3148a8SMichael Lange 
271130b0ce1bSStefano Zampini .seealso: DMPlexDistribute(), DMPlexCreateOverlap()
2712aa3148a8SMichael Lange @*/
2713aa3148a8SMichael Lange PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf)
2714aa3148a8SMichael Lange {
27156e203dd9SStefano Zampini   PetscMPIInt     rank;
27166e203dd9SStefano Zampini   PetscInt        n, numRemote, p, numPoints, pStart, pEnd, idx = 0, nNeighbors;
2717aa3148a8SMichael Lange   PetscSFNode    *remotePoints;
27186e203dd9SStefano Zampini   IS              remoteRootIS, neighborsIS;
27196e203dd9SStefano Zampini   const PetscInt *remoteRoots, *neighbors;
2720aa3148a8SMichael Lange   PetscErrorCode ierr;
2721aa3148a8SMichael Lange 
2722aa3148a8SMichael Lange   PetscFunctionBegin;
272330b0ce1bSStefano Zampini   ierr = PetscLogEventBegin(DMPLEX_PartLabelCreateSF,dm,0,0,0);CHKERRQ(ierr);
272443f7d02bSMichael Lange   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr);
2725aa3148a8SMichael Lange 
27266e203dd9SStefano Zampini   ierr = DMLabelGetValueIS(label, &neighborsIS);CHKERRQ(ierr);
27276e203dd9SStefano Zampini #if 0
27286e203dd9SStefano Zampini   {
27296e203dd9SStefano Zampini     IS is;
27306e203dd9SStefano Zampini     ierr = ISDuplicate(neighborsIS, &is);CHKERRQ(ierr);
27316e203dd9SStefano Zampini     ierr = ISSort(is);CHKERRQ(ierr);
27326e203dd9SStefano Zampini     ierr = ISDestroy(&neighborsIS);CHKERRQ(ierr);
27336e203dd9SStefano Zampini     neighborsIS = is;
27346e203dd9SStefano Zampini   }
27356e203dd9SStefano Zampini #endif
27366e203dd9SStefano Zampini   ierr = ISGetLocalSize(neighborsIS, &nNeighbors);CHKERRQ(ierr);
27376e203dd9SStefano Zampini   ierr = ISGetIndices(neighborsIS, &neighbors);CHKERRQ(ierr);
27386e203dd9SStefano Zampini   for (numRemote = 0, n = 0; n < nNeighbors; ++n) {
27396e203dd9SStefano Zampini     ierr = DMLabelGetStratumSize(label, neighbors[n], &numPoints);CHKERRQ(ierr);
2740aa3148a8SMichael Lange     numRemote += numPoints;
2741aa3148a8SMichael Lange   }
2742aa3148a8SMichael Lange   ierr = PetscMalloc1(numRemote, &remotePoints);CHKERRQ(ierr);
274343f7d02bSMichael Lange   /* Put owned points first */
274443f7d02bSMichael Lange   ierr = DMLabelGetStratumSize(label, rank, &numPoints);CHKERRQ(ierr);
274543f7d02bSMichael Lange   if (numPoints > 0) {
274643f7d02bSMichael Lange     ierr = DMLabelGetStratumIS(label, rank, &remoteRootIS);CHKERRQ(ierr);
274743f7d02bSMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
274843f7d02bSMichael Lange     for (p = 0; p < numPoints; p++) {
274943f7d02bSMichael Lange       remotePoints[idx].index = remoteRoots[p];
275043f7d02bSMichael Lange       remotePoints[idx].rank = rank;
275143f7d02bSMichael Lange       idx++;
275243f7d02bSMichael Lange     }
275343f7d02bSMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
275443f7d02bSMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
275543f7d02bSMichael Lange   }
275643f7d02bSMichael Lange   /* Now add remote points */
27576e203dd9SStefano Zampini   for (n = 0; n < nNeighbors; ++n) {
27586e203dd9SStefano Zampini     const PetscInt nn = neighbors[n];
27596e203dd9SStefano Zampini 
27606e203dd9SStefano Zampini     ierr = DMLabelGetStratumSize(label, nn, &numPoints);CHKERRQ(ierr);
27616e203dd9SStefano Zampini     if (nn == rank || numPoints <= 0) continue;
27626e203dd9SStefano Zampini     ierr = DMLabelGetStratumIS(label, nn, &remoteRootIS);CHKERRQ(ierr);
2763aa3148a8SMichael Lange     ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2764aa3148a8SMichael Lange     for (p = 0; p < numPoints; p++) {
2765aa3148a8SMichael Lange       remotePoints[idx].index = remoteRoots[p];
27666e203dd9SStefano Zampini       remotePoints[idx].rank = nn;
2767aa3148a8SMichael Lange       idx++;
2768aa3148a8SMichael Lange     }
2769aa3148a8SMichael Lange     ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr);
2770aa3148a8SMichael Lange     ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr);
2771aa3148a8SMichael Lange   }
2772aa3148a8SMichael Lange   ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), sf);CHKERRQ(ierr);
2773aa3148a8SMichael Lange   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
2774aa3148a8SMichael Lange   ierr = PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
277530b0ce1bSStefano Zampini   ierr = PetscSFSetUp(*sf);CHKERRQ(ierr);
27766e203dd9SStefano Zampini   ierr = ISDestroy(&neighborsIS);CHKERRQ(ierr);
277730b0ce1bSStefano Zampini   ierr = PetscLogEventEnd(DMPLEX_PartLabelCreateSF,dm,0,0,0);CHKERRQ(ierr);
277870034214SMatthew G. Knepley   PetscFunctionReturn(0);
277970034214SMatthew G. Knepley }
2780cb87ef4cSFlorian Wechsung 
27816a3739e5SFlorian Wechsung /* The two functions below are used by DMPlexRebalanceSharedPoints which errors
27826a3739e5SFlorian Wechsung  * when PETSc is built without ParMETIS. To avoid -Wunused-function, we take
27836a3739e5SFlorian Wechsung  * them out in that case. */
27846a3739e5SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
27857a82c785SFlorian Wechsung /*@C
27867f57c1a4SFlorian Wechsung 
27877f57c1a4SFlorian Wechsung   DMPlexRewriteSF - Rewrites the ownership of the SF of a DM (in place).
27887f57c1a4SFlorian Wechsung 
27897f57c1a4SFlorian Wechsung   Input parameters:
27907f57c1a4SFlorian Wechsung + dm                - The DMPlex object.
2791fe2efc57SMark . n                 - The number of points.
2792fe2efc57SMark . pointsToRewrite   - The points in the SF whose ownership will change.
2793fe2efc57SMark . targetOwners      - New owner for each element in pointsToRewrite.
2794fe2efc57SMark - degrees           - Degrees of the points in the SF as obtained by PetscSFComputeDegreeBegin/PetscSFComputeDegreeEnd.
27957f57c1a4SFlorian Wechsung 
27967f57c1a4SFlorian Wechsung   Level: developer
27977f57c1a4SFlorian Wechsung 
27987f57c1a4SFlorian Wechsung @*/
27997f57c1a4SFlorian Wechsung static PetscErrorCode DMPlexRewriteSF(DM dm, PetscInt n, PetscInt *pointsToRewrite, PetscInt *targetOwners, const PetscInt *degrees)
28007f57c1a4SFlorian Wechsung {
28017f57c1a4SFlorian Wechsung   PetscInt      ierr, pStart, pEnd, i, j, counter, leafCounter, sumDegrees, nroots, nleafs;
28027f57c1a4SFlorian Wechsung   PetscInt     *cumSumDegrees, *newOwners, *newNumbers, *rankOnLeafs, *locationsOfLeafs, *remoteLocalPointOfLeafs, *points, *leafsNew;
28037f57c1a4SFlorian Wechsung   PetscSFNode  *leafLocationsNew;
28047f57c1a4SFlorian Wechsung   const         PetscSFNode *iremote;
28057f57c1a4SFlorian Wechsung   const         PetscInt *ilocal;
28067f57c1a4SFlorian Wechsung   PetscBool    *isLeaf;
28077f57c1a4SFlorian Wechsung   PetscSF       sf;
28087f57c1a4SFlorian Wechsung   MPI_Comm      comm;
28095a30b08bSFlorian Wechsung   PetscMPIInt   rank, size;
28107f57c1a4SFlorian Wechsung 
28117f57c1a4SFlorian Wechsung   PetscFunctionBegin;
28127f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
28137f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
28147f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
28157f57c1a4SFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
28167f57c1a4SFlorian Wechsung 
28177f57c1a4SFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
28187f57c1a4SFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote); CHKERRQ(ierr);
28197f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
28207f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28217f57c1a4SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
28227f57c1a4SFlorian Wechsung   }
28237f57c1a4SFlorian Wechsung   for (i=0; i<nleafs; i++) {
28247f57c1a4SFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
28257f57c1a4SFlorian Wechsung   }
28267f57c1a4SFlorian Wechsung 
28277f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart+1, &cumSumDegrees);CHKERRQ(ierr);
28287f57c1a4SFlorian Wechsung   cumSumDegrees[0] = 0;
28297f57c1a4SFlorian Wechsung   for (i=1; i<=pEnd-pStart; i++) {
28307f57c1a4SFlorian Wechsung     cumSumDegrees[i] = cumSumDegrees[i-1] + degrees[i-1];
28317f57c1a4SFlorian Wechsung   }
28327f57c1a4SFlorian Wechsung   sumDegrees = cumSumDegrees[pEnd-pStart];
28337f57c1a4SFlorian Wechsung   /* get the location of my leafs (we have sumDegrees many leafs pointing at our roots) */
28347f57c1a4SFlorian Wechsung 
28357f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &locationsOfLeafs);CHKERRQ(ierr);
28367f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &rankOnLeafs);CHKERRQ(ierr);
28377f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28387f57c1a4SFlorian Wechsung     rankOnLeafs[i] = rank;
28397f57c1a4SFlorian Wechsung   }
28407f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
28417f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, rankOnLeafs, locationsOfLeafs);CHKERRQ(ierr);
28427f57c1a4SFlorian Wechsung   ierr = PetscFree(rankOnLeafs);CHKERRQ(ierr);
28437f57c1a4SFlorian Wechsung 
28447f57c1a4SFlorian Wechsung   /* get the remote local points of my leaves */
28457f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(sumDegrees, &remoteLocalPointOfLeafs);CHKERRQ(ierr);
28467f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &points);CHKERRQ(ierr);
28477f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28487f57c1a4SFlorian Wechsung     points[i] = pStart+i;
28497f57c1a4SFlorian Wechsung   }
28507f57c1a4SFlorian Wechsung   ierr = PetscSFGatherBegin(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
28517f57c1a4SFlorian Wechsung   ierr = PetscSFGatherEnd(sf, MPIU_INT, points, remoteLocalPointOfLeafs);CHKERRQ(ierr);
28527f57c1a4SFlorian Wechsung   ierr = PetscFree(points);CHKERRQ(ierr);
28537f57c1a4SFlorian Wechsung   /* Figure out the new owners of the vertices that are up for grabs and their numbers on the new owners */
28547f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newOwners);CHKERRQ(ierr);
28557f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &newNumbers);CHKERRQ(ierr);
28567f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28577f57c1a4SFlorian Wechsung     newOwners[i] = -1;
28587f57c1a4SFlorian Wechsung     newNumbers[i] = -1;
28597f57c1a4SFlorian Wechsung   }
28607f57c1a4SFlorian Wechsung   {
28617f57c1a4SFlorian Wechsung     PetscInt oldNumber, newNumber, oldOwner, newOwner;
28627f57c1a4SFlorian Wechsung     for (i=0; i<n; i++) {
28637f57c1a4SFlorian Wechsung       oldNumber = pointsToRewrite[i];
28647f57c1a4SFlorian Wechsung       newNumber = -1;
28657f57c1a4SFlorian Wechsung       oldOwner = rank;
28667f57c1a4SFlorian Wechsung       newOwner = targetOwners[i];
28677f57c1a4SFlorian Wechsung       if (oldOwner == newOwner) {
28687f57c1a4SFlorian Wechsung         newNumber = oldNumber;
28697f57c1a4SFlorian Wechsung       } else {
28707f57c1a4SFlorian Wechsung         for (j=0; j<degrees[oldNumber]; j++) {
28717f57c1a4SFlorian Wechsung           if (locationsOfLeafs[cumSumDegrees[oldNumber]+j] == newOwner) {
28727f57c1a4SFlorian Wechsung             newNumber = remoteLocalPointOfLeafs[cumSumDegrees[oldNumber]+j];
28737f57c1a4SFlorian Wechsung             break;
28747f57c1a4SFlorian Wechsung           }
28757f57c1a4SFlorian Wechsung         }
28767f57c1a4SFlorian Wechsung       }
28777f57c1a4SFlorian Wechsung       if (newNumber == -1) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Couldn't find the new owner of vertex.");
28787f57c1a4SFlorian Wechsung 
28797f57c1a4SFlorian Wechsung       newOwners[oldNumber] = newOwner;
28807f57c1a4SFlorian Wechsung       newNumbers[oldNumber] = newNumber;
28817f57c1a4SFlorian Wechsung     }
28827f57c1a4SFlorian Wechsung   }
28837f57c1a4SFlorian Wechsung   ierr = PetscFree(cumSumDegrees);CHKERRQ(ierr);
28847f57c1a4SFlorian Wechsung   ierr = PetscFree(locationsOfLeafs);CHKERRQ(ierr);
28857f57c1a4SFlorian Wechsung   ierr = PetscFree(remoteLocalPointOfLeafs);CHKERRQ(ierr);
28867f57c1a4SFlorian Wechsung 
28877f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
28887f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newOwners, newOwners);CHKERRQ(ierr);
28897f57c1a4SFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
28907f57c1a4SFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, newNumbers, newNumbers);CHKERRQ(ierr);
28917f57c1a4SFlorian Wechsung 
28927f57c1a4SFlorian Wechsung   /* Now count how many leafs we have on each processor. */
28937f57c1a4SFlorian Wechsung   leafCounter=0;
28947f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
28957f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
28967f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
28977f57c1a4SFlorian Wechsung         leafCounter++;
28987f57c1a4SFlorian Wechsung       }
28997f57c1a4SFlorian Wechsung     } else {
29007f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
29017f57c1a4SFlorian Wechsung         leafCounter++;
29027f57c1a4SFlorian Wechsung       }
29037f57c1a4SFlorian Wechsung     }
29047f57c1a4SFlorian Wechsung   }
29057f57c1a4SFlorian Wechsung 
29067f57c1a4SFlorian Wechsung   /* Now set up the new sf by creating the leaf arrays */
29077f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafsNew);CHKERRQ(ierr);
29087f57c1a4SFlorian Wechsung   ierr = PetscMalloc1(leafCounter, &leafLocationsNew);CHKERRQ(ierr);
29097f57c1a4SFlorian Wechsung 
29107f57c1a4SFlorian Wechsung   leafCounter = 0;
29117f57c1a4SFlorian Wechsung   counter = 0;
29127f57c1a4SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
29137f57c1a4SFlorian Wechsung     if (newOwners[i] >= 0) {
29147f57c1a4SFlorian Wechsung       if (newOwners[i] != rank) {
29157f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
29167f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = newOwners[i];
29177f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = newNumbers[i];
29187f57c1a4SFlorian Wechsung         leafCounter++;
29197f57c1a4SFlorian Wechsung       }
29207f57c1a4SFlorian Wechsung     } else {
29217f57c1a4SFlorian Wechsung       if (isLeaf[i]) {
29227f57c1a4SFlorian Wechsung         leafsNew[leafCounter] = i;
29237f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].rank = iremote[counter].rank;
29247f57c1a4SFlorian Wechsung         leafLocationsNew[leafCounter].index = iremote[counter].index;
29257f57c1a4SFlorian Wechsung         leafCounter++;
29267f57c1a4SFlorian Wechsung       }
29277f57c1a4SFlorian Wechsung     }
29287f57c1a4SFlorian Wechsung     if (isLeaf[i]) {
29297f57c1a4SFlorian Wechsung       counter++;
29307f57c1a4SFlorian Wechsung     }
29317f57c1a4SFlorian Wechsung   }
29327f57c1a4SFlorian Wechsung 
29337f57c1a4SFlorian Wechsung   ierr = PetscSFSetGraph(sf, nroots, leafCounter, leafsNew, PETSC_OWN_POINTER, leafLocationsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
29347f57c1a4SFlorian Wechsung   ierr = PetscFree(newOwners);CHKERRQ(ierr);
29357f57c1a4SFlorian Wechsung   ierr = PetscFree(newNumbers);CHKERRQ(ierr);
29367f57c1a4SFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
29377f57c1a4SFlorian Wechsung   PetscFunctionReturn(0);
29387f57c1a4SFlorian Wechsung }
29397f57c1a4SFlorian Wechsung 
2940125d2a8fSFlorian Wechsung static PetscErrorCode DMPlexViewDistribution(MPI_Comm comm, PetscInt n, PetscInt skip, PetscInt *vtxwgt, PetscInt *part, PetscViewer viewer)
2941125d2a8fSFlorian Wechsung {
29425a30b08bSFlorian Wechsung   PetscInt *distribution, min, max, sum, i, ierr;
29435a30b08bSFlorian Wechsung   PetscMPIInt rank, size;
2944125d2a8fSFlorian Wechsung   PetscFunctionBegin;
2945125d2a8fSFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
2946125d2a8fSFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2947125d2a8fSFlorian Wechsung   ierr = PetscCalloc1(size, &distribution);CHKERRQ(ierr);
2948125d2a8fSFlorian Wechsung   for (i=0; i<n; i++) {
2949125d2a8fSFlorian Wechsung     if (part) distribution[part[i]] += vtxwgt[skip*i];
2950125d2a8fSFlorian Wechsung     else distribution[rank] += vtxwgt[skip*i];
2951125d2a8fSFlorian Wechsung   }
2952125d2a8fSFlorian Wechsung   ierr = MPI_Allreduce(MPI_IN_PLACE, distribution, size, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
2953125d2a8fSFlorian Wechsung   min = distribution[0];
2954125d2a8fSFlorian Wechsung   max = distribution[0];
2955125d2a8fSFlorian Wechsung   sum = distribution[0];
2956125d2a8fSFlorian Wechsung   for (i=1; i<size; i++) {
2957125d2a8fSFlorian Wechsung     if (distribution[i]<min) min=distribution[i];
2958125d2a8fSFlorian Wechsung     if (distribution[i]>max) max=distribution[i];
2959125d2a8fSFlorian Wechsung     sum += distribution[i];
2960125d2a8fSFlorian Wechsung   }
2961125d2a8fSFlorian Wechsung   ierr = PetscViewerASCIIPrintf(viewer, "Min: %D, Avg: %D, Max: %D, Balance: %f\n", min, sum/size, max, (max*1.*size)/sum);CHKERRQ(ierr);
2962125d2a8fSFlorian Wechsung   ierr = PetscFree(distribution);CHKERRQ(ierr);
2963125d2a8fSFlorian Wechsung   PetscFunctionReturn(0);
2964125d2a8fSFlorian Wechsung }
2965125d2a8fSFlorian Wechsung 
29666a3739e5SFlorian Wechsung #endif
29676a3739e5SFlorian Wechsung 
2968cb87ef4cSFlorian Wechsung /*@
29695dc86ac1SFlorian Wechsung   DMPlexRebalanceSharedPoints - Redistribute points in the plex that are shared in order to achieve better balancing. This routine updates the PointSF of the DM inplace.
2970cb87ef4cSFlorian Wechsung 
2971cb87ef4cSFlorian Wechsung   Input parameters:
2972ed44d270SFlorian Wechsung + dm               - The DMPlex object.
2973fe2efc57SMark . entityDepth      - depth of the entity to balance (0 -> balance vertices).
2974fe2efc57SMark . useInitialGuess  - whether to use the current distribution as initial guess (only used by ParMETIS).
2975fe2efc57SMark - parallel         - whether to use ParMETIS and do the partition in parallel or whether to gather the graph onto a single process and use METIS.
2976cb87ef4cSFlorian Wechsung 
29778b879b41SFlorian Wechsung   Output parameters:
2978fe2efc57SMark . success          - whether the graph partitioning was successful or not. If not, try useInitialGuess=True and parallel=True.
29798b879b41SFlorian Wechsung 
298090ea27d8SSatish Balay   Level: intermediate
2981cb87ef4cSFlorian Wechsung 
2982cb87ef4cSFlorian Wechsung @*/
2983cb87ef4cSFlorian Wechsung 
29848b879b41SFlorian Wechsung PetscErrorCode DMPlexRebalanceSharedPoints(DM dm, PetscInt entityDepth, PetscBool useInitialGuess, PetscBool parallel, PetscBool *success)
2985cb87ef4cSFlorian Wechsung {
298641525646SFlorian Wechsung #if defined(PETSC_HAVE_PARMETIS)
2987cb87ef4cSFlorian Wechsung   PetscSF     sf;
29880faf6628SFlorian Wechsung   PetscInt    ierr, i, j, idx, jdx;
29897f57c1a4SFlorian Wechsung   PetscInt    eBegin, eEnd, nroots, nleafs, pStart, pEnd;
29907f57c1a4SFlorian Wechsung   const       PetscInt *degrees, *ilocal;
29917f57c1a4SFlorian Wechsung   const       PetscSFNode *iremote;
2992cb87ef4cSFlorian Wechsung   PetscBool   *toBalance, *isLeaf, *isExclusivelyOwned, *isNonExclusivelyOwned;
2993cf818975SFlorian Wechsung   PetscInt    numExclusivelyOwned, numNonExclusivelyOwned;
2994cb87ef4cSFlorian Wechsung   PetscMPIInt rank, size;
29957f57c1a4SFlorian Wechsung   PetscInt    *globalNumbersOfLocalOwnedVertices, *leafGlobalNumbers;
29965dc86ac1SFlorian Wechsung   const       PetscInt *cumSumVertices;
2997cb87ef4cSFlorian Wechsung   PetscInt    offset, counter;
29987f57c1a4SFlorian Wechsung   PetscInt    lenadjncy;
2999cb87ef4cSFlorian Wechsung   PetscInt    *xadj, *adjncy, *vtxwgt;
3000cb87ef4cSFlorian Wechsung   PetscInt    lenxadj;
3001cb87ef4cSFlorian Wechsung   PetscInt    *adjwgt = NULL;
3002cb87ef4cSFlorian Wechsung   PetscInt    *part, *options;
3003cf818975SFlorian Wechsung   PetscInt    nparts, wgtflag, numflag, ncon, edgecut;
3004cb87ef4cSFlorian Wechsung   real_t      *ubvec;
3005cb87ef4cSFlorian Wechsung   PetscInt    *firstVertices, *renumbering;
3006cb87ef4cSFlorian Wechsung   PetscInt    failed, failedGlobal;
3007cb87ef4cSFlorian Wechsung   MPI_Comm    comm;
30084baf1206SFlorian Wechsung   Mat         A, Apre;
300912617df9SFlorian Wechsung   const char *prefix = NULL;
30107d197802SFlorian Wechsung   PetscViewer       viewer;
30117d197802SFlorian Wechsung   PetscViewerFormat format;
30125a30b08bSFlorian Wechsung   PetscLayout layout;
301312617df9SFlorian Wechsung 
301412617df9SFlorian Wechsung   PetscFunctionBegin;
30158b879b41SFlorian Wechsung   if (success) *success = PETSC_FALSE;
30167f57c1a4SFlorian Wechsung   ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr);
30177f57c1a4SFlorian Wechsung   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
30187f57c1a4SFlorian Wechsung   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
30197f57c1a4SFlorian Wechsung   if (size==1) PetscFunctionReturn(0);
30207f57c1a4SFlorian Wechsung 
302141525646SFlorian Wechsung   ierr = PetscLogEventBegin(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
302241525646SFlorian Wechsung 
30235a30b08bSFlorian Wechsung   ierr = PetscOptionsGetViewer(comm,((PetscObject)dm)->options, prefix,"-dm_rebalance_partition_view",&viewer,&format,NULL);CHKERRQ(ierr);
30245dc86ac1SFlorian Wechsung   if (viewer) {
30255a30b08bSFlorian Wechsung     ierr = PetscViewerPushFormat(viewer,format);CHKERRQ(ierr);
30267d197802SFlorian Wechsung   }
30277d197802SFlorian Wechsung 
3028ed44d270SFlorian Wechsung   /* Figure out all points in the plex that we are interested in balancing. */
3029d5528e35SFlorian Wechsung   ierr = DMPlexGetDepthStratum(dm, entityDepth, &eBegin, &eEnd);CHKERRQ(ierr);
3030cb87ef4cSFlorian Wechsung   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3031cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &toBalance);CHKERRQ(ierr);
3032cf818975SFlorian Wechsung 
3033cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
30345a7e692eSFlorian Wechsung     toBalance[i] = (PetscBool)(i-pStart>=eBegin && i-pStart<eEnd);
3035cb87ef4cSFlorian Wechsung   }
3036cb87ef4cSFlorian Wechsung 
3037cf818975SFlorian Wechsung   /* There are three types of points:
3038cf818975SFlorian Wechsung    * exclusivelyOwned: points that are owned by this process and only seen by this process
3039cf818975SFlorian Wechsung    * nonExclusivelyOwned: points that are owned by this process but seen by at least another process
3040cf818975SFlorian Wechsung    * leaf: a point that is seen by this process but owned by a different process
3041cf818975SFlorian Wechsung    */
3042cb87ef4cSFlorian Wechsung   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
3043cb87ef4cSFlorian Wechsung   ierr = PetscSFGetGraph(sf, &nroots, &nleafs, &ilocal, &iremote); CHKERRQ(ierr);
3044cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isLeaf);CHKERRQ(ierr);
3045cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isNonExclusivelyOwned);CHKERRQ(ierr);
3046cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &isExclusivelyOwned);CHKERRQ(ierr);
3047cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3048cb87ef4cSFlorian Wechsung     isNonExclusivelyOwned[i] = PETSC_FALSE;
3049cb87ef4cSFlorian Wechsung     isExclusivelyOwned[i] = PETSC_FALSE;
3050cf818975SFlorian Wechsung     isLeaf[i] = PETSC_FALSE;
3051cb87ef4cSFlorian Wechsung   }
3052cf818975SFlorian Wechsung 
3053cf818975SFlorian Wechsung   /* start by marking all the leafs */
3054cb87ef4cSFlorian Wechsung   for (i=0; i<nleafs; i++) {
3055cb87ef4cSFlorian Wechsung     isLeaf[ilocal[i]-pStart] = PETSC_TRUE;
3056cb87ef4cSFlorian Wechsung   }
3057cb87ef4cSFlorian Wechsung 
3058cf818975SFlorian Wechsung   /* for an owned point, we can figure out whether another processor sees it or
3059cf818975SFlorian Wechsung    * not by calculating its degree */
30607f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeBegin(sf, &degrees);CHKERRQ(ierr);
30617f57c1a4SFlorian Wechsung   ierr = PetscSFComputeDegreeEnd(sf, &degrees);CHKERRQ(ierr);
3062cf818975SFlorian Wechsung 
3063cb87ef4cSFlorian Wechsung   numExclusivelyOwned = 0;
3064cb87ef4cSFlorian Wechsung   numNonExclusivelyOwned = 0;
3065cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3066cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
30677f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
3068cb87ef4cSFlorian Wechsung         isNonExclusivelyOwned[i] = PETSC_TRUE;
3069cb87ef4cSFlorian Wechsung         numNonExclusivelyOwned += 1;
3070cb87ef4cSFlorian Wechsung       } else {
3071cb87ef4cSFlorian Wechsung         if (!isLeaf[i]) {
3072cb87ef4cSFlorian Wechsung           isExclusivelyOwned[i] = PETSC_TRUE;
3073cb87ef4cSFlorian Wechsung           numExclusivelyOwned += 1;
3074cb87ef4cSFlorian Wechsung         }
3075cb87ef4cSFlorian Wechsung       }
3076cb87ef4cSFlorian Wechsung     }
3077cb87ef4cSFlorian Wechsung   }
3078cb87ef4cSFlorian Wechsung 
3079cf818975SFlorian Wechsung   /* We are going to build a graph with one vertex per core representing the
3080cf818975SFlorian Wechsung    * exclusively owned points and then one vertex per nonExclusively owned
3081cf818975SFlorian Wechsung    * point. */
3082cb87ef4cSFlorian Wechsung 
30835dc86ac1SFlorian Wechsung   ierr = PetscLayoutCreate(comm, &layout);CHKERRQ(ierr);
30845dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetLocalSize(layout, 1 + numNonExclusivelyOwned);CHKERRQ(ierr);
30855dc86ac1SFlorian Wechsung   ierr = PetscLayoutSetUp(layout);CHKERRQ(ierr);
30865dc86ac1SFlorian Wechsung   ierr = PetscLayoutGetRanges(layout, &cumSumVertices);CHKERRQ(ierr);
30875dc86ac1SFlorian Wechsung 
3088cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
30895a427404SJunchao Zhang   for (i=0; i<pEnd-pStart; i++) {globalNumbersOfLocalOwnedVertices[i] = pStart - 1;}
3090cb87ef4cSFlorian Wechsung   offset = cumSumVertices[rank];
3091cb87ef4cSFlorian Wechsung   counter = 0;
3092cb87ef4cSFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
3093cb87ef4cSFlorian Wechsung     if (toBalance[i]) {
30947f57c1a4SFlorian Wechsung       if (degrees[i] > 0) {
3095cb87ef4cSFlorian Wechsung         globalNumbersOfLocalOwnedVertices[i] = counter + 1 + offset;
3096cb87ef4cSFlorian Wechsung         counter++;
3097cb87ef4cSFlorian Wechsung       }
3098cb87ef4cSFlorian Wechsung     }
3099cb87ef4cSFlorian Wechsung   }
3100cb87ef4cSFlorian Wechsung 
3101cb87ef4cSFlorian Wechsung   /* send the global numbers of vertices I own to the leafs so that they know to connect to it */
3102cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(pEnd-pStart, &leafGlobalNumbers);CHKERRQ(ierr);
3103cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastBegin(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
3104cb87ef4cSFlorian Wechsung   ierr = PetscSFBcastEnd(sf, MPIU_INT, globalNumbersOfLocalOwnedVertices, leafGlobalNumbers);CHKERRQ(ierr);
3105cb87ef4cSFlorian Wechsung 
31060faf6628SFlorian Wechsung   /* Now start building the data structure for ParMETIS */
3107cb87ef4cSFlorian Wechsung 
31084baf1206SFlorian Wechsung   ierr = MatCreate(comm, &Apre);CHKERRQ(ierr);
31094baf1206SFlorian Wechsung   ierr = MatSetType(Apre, MATPREALLOCATOR);CHKERRQ(ierr);
31104baf1206SFlorian Wechsung   ierr = MatSetSizes(Apre, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
31114baf1206SFlorian Wechsung   ierr = MatSetUp(Apre);CHKERRQ(ierr);
31128c9a1619SFlorian Wechsung 
31138c9a1619SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
31148c9a1619SFlorian Wechsung     if (toBalance[i]) {
31150faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
31160faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
31170faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
31180faf6628SFlorian Wechsung       else continue;
31190faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
31200faf6628SFlorian Wechsung       ierr = MatSetValue(Apre, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
31214baf1206SFlorian Wechsung     }
31224baf1206SFlorian Wechsung   }
31234baf1206SFlorian Wechsung 
31244baf1206SFlorian Wechsung   ierr = MatAssemblyBegin(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
31254baf1206SFlorian Wechsung   ierr = MatAssemblyEnd(Apre, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
31264baf1206SFlorian Wechsung 
31274baf1206SFlorian Wechsung   ierr = MatCreate(comm, &A);CHKERRQ(ierr);
31284baf1206SFlorian Wechsung   ierr = MatSetType(A, MATMPIAIJ);CHKERRQ(ierr);
31294baf1206SFlorian Wechsung   ierr = MatSetSizes(A, 1+numNonExclusivelyOwned, 1+numNonExclusivelyOwned, cumSumVertices[size], cumSumVertices[size]);CHKERRQ(ierr);
31304baf1206SFlorian Wechsung   ierr = MatPreallocatorPreallocate(Apre, PETSC_FALSE, A);CHKERRQ(ierr);
31314baf1206SFlorian Wechsung   ierr = MatDestroy(&Apre);CHKERRQ(ierr);
31324baf1206SFlorian Wechsung 
31334baf1206SFlorian Wechsung   for (i=0; i<pEnd-pStart; i++) {
31344baf1206SFlorian Wechsung     if (toBalance[i]) {
31350faf6628SFlorian Wechsung       idx = cumSumVertices[rank];
31360faf6628SFlorian Wechsung       if (isNonExclusivelyOwned[i]) jdx = globalNumbersOfLocalOwnedVertices[i];
31370faf6628SFlorian Wechsung       else if (isLeaf[i]) jdx = leafGlobalNumbers[i];
31380faf6628SFlorian Wechsung       else continue;
31390faf6628SFlorian Wechsung       ierr = MatSetValue(A, idx, jdx, 1, INSERT_VALUES);CHKERRQ(ierr);
31400faf6628SFlorian Wechsung       ierr = MatSetValue(A, jdx, idx, 1, INSERT_VALUES);CHKERRQ(ierr);
31410941debbSFlorian Wechsung     }
31420941debbSFlorian Wechsung   }
31438c9a1619SFlorian Wechsung 
31448c9a1619SFlorian Wechsung   ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
31458c9a1619SFlorian Wechsung   ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
31464baf1206SFlorian Wechsung   ierr = PetscFree(leafGlobalNumbers);CHKERRQ(ierr);
31474baf1206SFlorian Wechsung   ierr = PetscFree(globalNumbersOfLocalOwnedVertices);CHKERRQ(ierr);
31484baf1206SFlorian Wechsung 
314941525646SFlorian Wechsung   nparts = size;
315041525646SFlorian Wechsung   wgtflag = 2;
315141525646SFlorian Wechsung   numflag = 0;
315241525646SFlorian Wechsung   ncon = 2;
315341525646SFlorian Wechsung   real_t *tpwgts;
315441525646SFlorian Wechsung   ierr = PetscMalloc1(ncon * nparts, &tpwgts);CHKERRQ(ierr);
315541525646SFlorian Wechsung   for (i=0; i<ncon*nparts; i++) {
315641525646SFlorian Wechsung     tpwgts[i] = 1./(nparts);
315741525646SFlorian Wechsung   }
315841525646SFlorian Wechsung 
315941525646SFlorian Wechsung   ierr = PetscMalloc1(ncon, &ubvec);CHKERRQ(ierr);
316041525646SFlorian Wechsung   ubvec[0] = 1.01;
31615a30b08bSFlorian Wechsung   ubvec[1] = 1.01;
31628c9a1619SFlorian Wechsung   lenadjncy = 0;
31638c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
31648c9a1619SFlorian Wechsung     PetscInt temp=0;
31658c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
31668c9a1619SFlorian Wechsung     lenadjncy += temp;
31678c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, NULL, NULL);CHKERRQ(ierr);
31688c9a1619SFlorian Wechsung   }
31698c9a1619SFlorian Wechsung   ierr = PetscMalloc1(lenadjncy, &adjncy);CHKERRQ(ierr);
31707407ba93SFlorian Wechsung   lenxadj = 2 + numNonExclusivelyOwned;
31710941debbSFlorian Wechsung   ierr = PetscMalloc1(lenxadj, &xadj);CHKERRQ(ierr);
31720941debbSFlorian Wechsung   xadj[0] = 0;
31738c9a1619SFlorian Wechsung   counter = 0;
31748c9a1619SFlorian Wechsung   for (i=0; i<1+numNonExclusivelyOwned; i++) {
31752953a68cSFlorian Wechsung     PetscInt        temp=0;
31762953a68cSFlorian Wechsung     const PetscInt *cols;
31778c9a1619SFlorian Wechsung     ierr = MatGetRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
3178580bdb30SBarry Smith     ierr = PetscArraycpy(&adjncy[counter], cols, temp);CHKERRQ(ierr);
31798c9a1619SFlorian Wechsung     counter += temp;
31800941debbSFlorian Wechsung     xadj[i+1] = counter;
31818c9a1619SFlorian Wechsung     ierr = MatRestoreRow(A, cumSumVertices[rank] + i, &temp, &cols, NULL);CHKERRQ(ierr);
31828c9a1619SFlorian Wechsung   }
31838c9a1619SFlorian Wechsung 
3184cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(cumSumVertices[rank+1]-cumSumVertices[rank], &part);CHKERRQ(ierr);
318541525646SFlorian Wechsung   ierr = PetscMalloc1(ncon*(1 + numNonExclusivelyOwned), &vtxwgt);CHKERRQ(ierr);
318641525646SFlorian Wechsung   vtxwgt[0] = numExclusivelyOwned;
318741525646SFlorian Wechsung   if (ncon>1) vtxwgt[1] = 1;
318841525646SFlorian Wechsung   for (i=0; i<numNonExclusivelyOwned; i++) {
318941525646SFlorian Wechsung     vtxwgt[ncon*(i+1)] = 1;
319041525646SFlorian Wechsung     if (ncon>1) vtxwgt[ncon*(i+1)+1] = 0;
319141525646SFlorian Wechsung   }
31928c9a1619SFlorian Wechsung 
31935dc86ac1SFlorian Wechsung   if (viewer) {
31947d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Attempt rebalancing of shared points of depth %D on interface of mesh distribution.\n", entityDepth);CHKERRQ(ierr);
31957d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Size of generated auxiliary graph: %D\n", cumSumVertices[size]);CHKERRQ(ierr);
319612617df9SFlorian Wechsung   }
319741525646SFlorian Wechsung   if (parallel) {
31985a30b08bSFlorian Wechsung     ierr = PetscMalloc1(4, &options);CHKERRQ(ierr);
31995a30b08bSFlorian Wechsung     options[0] = 1;
32005a30b08bSFlorian Wechsung     options[1] = 0; /* Verbosity */
32015a30b08bSFlorian Wechsung     options[2] = 0; /* Seed */
32025a30b08bSFlorian Wechsung     options[3] = PARMETIS_PSR_COUPLED; /* Seed */
32035dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using ParMETIS to partition graph.\n");CHKERRQ(ierr); }
32048c9a1619SFlorian Wechsung     if (useInitialGuess) {
32055dc86ac1SFlorian Wechsung       if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using current distribution of points as initial guess.\n");CHKERRQ(ierr); }
32068c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_RefineKway");
32075dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_RefineKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
320806b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_RefineKway()");
32098c9a1619SFlorian Wechsung       PetscStackPop;
32108c9a1619SFlorian Wechsung     } else {
32118c9a1619SFlorian Wechsung       PetscStackPush("ParMETIS_V3_PartKway");
32125dc86ac1SFlorian Wechsung       ierr = ParMETIS_V3_PartKway((PetscInt*)cumSumVertices, xadj, adjncy, vtxwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgecut, part, &comm);
32138c9a1619SFlorian Wechsung       PetscStackPop;
321406b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
32158c9a1619SFlorian Wechsung     }
3216ef74bcceSFlorian Wechsung     ierr = PetscFree(options);CHKERRQ(ierr);
321741525646SFlorian Wechsung   } else {
32185dc86ac1SFlorian Wechsung     if (viewer) { ierr = PetscViewerASCIIPrintf(viewer, "Using METIS to partition graph.\n");CHKERRQ(ierr); }
321941525646SFlorian Wechsung     Mat As;
322041525646SFlorian Wechsung     PetscInt numRows;
322141525646SFlorian Wechsung     PetscInt *partGlobal;
322241525646SFlorian Wechsung     ierr = MatCreateRedundantMatrix(A, size, MPI_COMM_NULL, MAT_INITIAL_MATRIX, &As);CHKERRQ(ierr);
3223cb87ef4cSFlorian Wechsung 
322441525646SFlorian Wechsung     PetscInt *numExclusivelyOwnedAll;
322541525646SFlorian Wechsung     ierr = PetscMalloc1(size, &numExclusivelyOwnedAll);CHKERRQ(ierr);
322641525646SFlorian Wechsung     numExclusivelyOwnedAll[rank] = numExclusivelyOwned;
32272953a68cSFlorian Wechsung     ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,numExclusivelyOwnedAll,1,MPIU_INT,comm);CHKERRQ(ierr);
3228cb87ef4cSFlorian Wechsung 
322941525646SFlorian Wechsung     ierr = MatGetSize(As, &numRows, NULL);CHKERRQ(ierr);
323041525646SFlorian Wechsung     ierr = PetscMalloc1(numRows, &partGlobal);CHKERRQ(ierr);
32315dc86ac1SFlorian Wechsung     if (!rank) {
323241525646SFlorian Wechsung       PetscInt *adjncy_g, *xadj_g, *vtxwgt_g;
323341525646SFlorian Wechsung       lenadjncy = 0;
323441525646SFlorian Wechsung 
323541525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
323641525646SFlorian Wechsung         PetscInt temp=0;
323741525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
323841525646SFlorian Wechsung         lenadjncy += temp;
323941525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, NULL, NULL);CHKERRQ(ierr);
324041525646SFlorian Wechsung       }
324141525646SFlorian Wechsung       ierr = PetscMalloc1(lenadjncy, &adjncy_g);CHKERRQ(ierr);
324241525646SFlorian Wechsung       lenxadj = 1 + numRows;
324341525646SFlorian Wechsung       ierr = PetscMalloc1(lenxadj, &xadj_g);CHKERRQ(ierr);
324441525646SFlorian Wechsung       xadj_g[0] = 0;
324541525646SFlorian Wechsung       counter = 0;
324641525646SFlorian Wechsung       for (i=0; i<numRows; i++) {
32472953a68cSFlorian Wechsung         PetscInt        temp=0;
32482953a68cSFlorian Wechsung         const PetscInt *cols;
324941525646SFlorian Wechsung         ierr = MatGetRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
3250580bdb30SBarry Smith         ierr = PetscArraycpy(&adjncy_g[counter], cols, temp);CHKERRQ(ierr);
325141525646SFlorian Wechsung         counter += temp;
325241525646SFlorian Wechsung         xadj_g[i+1] = counter;
325341525646SFlorian Wechsung         ierr = MatRestoreRow(As, i, &temp, &cols, NULL);CHKERRQ(ierr);
325441525646SFlorian Wechsung       }
325541525646SFlorian Wechsung       ierr = PetscMalloc1(2*numRows, &vtxwgt_g);CHKERRQ(ierr);
325641525646SFlorian Wechsung       for (i=0; i<size; i++){
325741525646SFlorian Wechsung         vtxwgt_g[ncon*cumSumVertices[i]] = numExclusivelyOwnedAll[i];
325841525646SFlorian Wechsung         if (ncon>1) vtxwgt_g[ncon*cumSumVertices[i]+1] = 1;
325941525646SFlorian Wechsung         for (j=cumSumVertices[i]+1; j<cumSumVertices[i+1]; j++) {
326041525646SFlorian Wechsung           vtxwgt_g[ncon*j] = 1;
326141525646SFlorian Wechsung           if (ncon>1) vtxwgt_g[2*j+1] = 0;
326241525646SFlorian Wechsung         }
326341525646SFlorian Wechsung       }
326441525646SFlorian Wechsung       ierr = PetscMalloc1(64, &options);CHKERRQ(ierr);
326541525646SFlorian Wechsung       ierr = METIS_SetDefaultOptions(options); /* initialize all defaults */
326606b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_SetDefaultOptions()");
326741525646SFlorian Wechsung       options[METIS_OPTION_CONTIG] = 1;
326841525646SFlorian Wechsung       PetscStackPush("METIS_PartGraphKway");
326906b3913eSFlorian Wechsung       ierr = METIS_PartGraphKway(&numRows, &ncon, xadj_g, adjncy_g, vtxwgt_g, NULL, NULL, &nparts, tpwgts, ubvec, options, &edgecut, partGlobal);
327041525646SFlorian Wechsung       PetscStackPop;
327106b3913eSFlorian Wechsung       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
3272ef74bcceSFlorian Wechsung       ierr = PetscFree(options);CHKERRQ(ierr);
327341525646SFlorian Wechsung       ierr = PetscFree(xadj_g);CHKERRQ(ierr);
327441525646SFlorian Wechsung       ierr = PetscFree(adjncy_g);CHKERRQ(ierr);
327541525646SFlorian Wechsung       ierr = PetscFree(vtxwgt_g);CHKERRQ(ierr);
327641525646SFlorian Wechsung     }
327741525646SFlorian Wechsung     ierr = PetscFree(numExclusivelyOwnedAll);CHKERRQ(ierr);
327841525646SFlorian Wechsung 
32795dc86ac1SFlorian Wechsung     /* Now scatter the parts array. */
32805dc86ac1SFlorian Wechsung     {
328181a13b52SFlorian Wechsung       PetscMPIInt *counts, *mpiCumSumVertices;
32825dc86ac1SFlorian Wechsung       ierr = PetscMalloc1(size, &counts);CHKERRQ(ierr);
328381a13b52SFlorian Wechsung       ierr = PetscMalloc1(size+1, &mpiCumSumVertices);CHKERRQ(ierr);
32845dc86ac1SFlorian Wechsung       for(i=0; i<size; i++) {
328581a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i+1] - cumSumVertices[i], &(counts[i]));CHKERRQ(ierr);
328641525646SFlorian Wechsung       }
328781a13b52SFlorian Wechsung       for(i=0; i<=size; i++) {
328881a13b52SFlorian Wechsung         ierr = PetscMPIIntCast(cumSumVertices[i], &(mpiCumSumVertices[i]));CHKERRQ(ierr);
328981a13b52SFlorian Wechsung       }
329081a13b52SFlorian Wechsung       ierr = MPI_Scatterv(partGlobal, counts, mpiCumSumVertices, MPIU_INT, part, counts[rank], MPIU_INT, 0, comm);CHKERRQ(ierr);
32915dc86ac1SFlorian Wechsung       ierr = PetscFree(counts);CHKERRQ(ierr);
329281a13b52SFlorian Wechsung       ierr = PetscFree(mpiCumSumVertices);CHKERRQ(ierr);
32935dc86ac1SFlorian Wechsung     }
32945dc86ac1SFlorian Wechsung 
329541525646SFlorian Wechsung     ierr = PetscFree(partGlobal);CHKERRQ(ierr);
32962953a68cSFlorian Wechsung     ierr = MatDestroy(&As);CHKERRQ(ierr);
329741525646SFlorian Wechsung   }
3298cb87ef4cSFlorian Wechsung 
32992953a68cSFlorian Wechsung   ierr = MatDestroy(&A);CHKERRQ(ierr);
3300cb87ef4cSFlorian Wechsung   ierr = PetscFree(ubvec);CHKERRQ(ierr);
3301cb87ef4cSFlorian Wechsung   ierr = PetscFree(tpwgts);CHKERRQ(ierr);
3302cb87ef4cSFlorian Wechsung 
3303cb87ef4cSFlorian Wechsung   /* Now rename the result so that the vertex resembling the exclusively owned points stays on the same rank */
3304cb87ef4cSFlorian Wechsung 
3305cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &firstVertices);CHKERRQ(ierr);
3306cb87ef4cSFlorian Wechsung   ierr = PetscMalloc1(size, &renumbering);CHKERRQ(ierr);
3307cb87ef4cSFlorian Wechsung   firstVertices[rank] = part[0];
33082953a68cSFlorian Wechsung   ierr = MPI_Allgather(MPI_IN_PLACE,0,MPI_DATATYPE_NULL,firstVertices,1,MPIU_INT,comm);CHKERRQ(ierr);
3309cb87ef4cSFlorian Wechsung   for (i=0; i<size; i++) {
3310cb87ef4cSFlorian Wechsung     renumbering[firstVertices[i]] = i;
3311cb87ef4cSFlorian Wechsung   }
3312cb87ef4cSFlorian Wechsung   for (i=0; i<cumSumVertices[rank+1]-cumSumVertices[rank]; i++) {
3313cb87ef4cSFlorian Wechsung     part[i] = renumbering[part[i]];
3314cb87ef4cSFlorian Wechsung   }
3315cb87ef4cSFlorian Wechsung   /* Check if the renumbering worked (this can fail when ParMETIS gives fewer partitions than there are processes) */
3316cb87ef4cSFlorian Wechsung   failed = (PetscInt)(part[0] != rank);
33172953a68cSFlorian Wechsung   ierr = MPI_Allreduce(&failed, &failedGlobal, 1, MPIU_INT, MPI_SUM, comm);CHKERRQ(ierr);
3318cb87ef4cSFlorian Wechsung 
33197f57c1a4SFlorian Wechsung   ierr = PetscFree(firstVertices);CHKERRQ(ierr);
33207f57c1a4SFlorian Wechsung   ierr = PetscFree(renumbering);CHKERRQ(ierr);
33217f57c1a4SFlorian Wechsung 
3322cb87ef4cSFlorian Wechsung   if (failedGlobal > 0) {
33237f57c1a4SFlorian Wechsung     ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
33247f57c1a4SFlorian Wechsung     ierr = PetscFree(xadj);CHKERRQ(ierr);
33257f57c1a4SFlorian Wechsung     ierr = PetscFree(adjncy);CHKERRQ(ierr);
33267f57c1a4SFlorian Wechsung     ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
33277f57c1a4SFlorian Wechsung     ierr = PetscFree(toBalance);CHKERRQ(ierr);
33287f57c1a4SFlorian Wechsung     ierr = PetscFree(isLeaf);CHKERRQ(ierr);
33297f57c1a4SFlorian Wechsung     ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
33307f57c1a4SFlorian Wechsung     ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
33317f57c1a4SFlorian Wechsung     ierr = PetscFree(part);CHKERRQ(ierr);
33327f57c1a4SFlorian Wechsung     if (viewer) {
333306b3913eSFlorian Wechsung       ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
333406b3913eSFlorian Wechsung       ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
33357f57c1a4SFlorian Wechsung     }
33367f57c1a4SFlorian Wechsung     ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
33378b879b41SFlorian Wechsung     PetscFunctionReturn(0);
3338cb87ef4cSFlorian Wechsung   }
3339cb87ef4cSFlorian Wechsung 
33407407ba93SFlorian Wechsung   /*Let's check how well we did distributing points*/
33415dc86ac1SFlorian Wechsung   if (viewer) {
33427d197802SFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Comparing number of owned entities of depth %D on each process before rebalancing, after rebalancing, and after consistency checks.\n", entityDepth);CHKERRQ(ierr);
3343125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Initial.     ");CHKERRQ(ierr);
3344125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, NULL, viewer);CHKERRQ(ierr);
3345125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "Rebalanced.  ");CHKERRQ(ierr);
3346125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
33477407ba93SFlorian Wechsung   }
33487407ba93SFlorian Wechsung 
3349cb87ef4cSFlorian Wechsung   /* Now check that every vertex is owned by a process that it is actually connected to. */
335041525646SFlorian Wechsung   for (i=1; i<=numNonExclusivelyOwned; i++) {
3351cb87ef4cSFlorian Wechsung     PetscInt loc = 0;
335241525646SFlorian Wechsung     ierr = PetscFindInt(cumSumVertices[part[i]], xadj[i+1]-xadj[i], &adjncy[xadj[i]], &loc);CHKERRQ(ierr);
33537407ba93SFlorian Wechsung     /* If not, then just set the owner to the original owner (hopefully a rare event, it means that a vertex has been isolated) */
3354cb87ef4cSFlorian Wechsung     if (loc<0) {
335541525646SFlorian Wechsung       part[i] = rank;
3356cb87ef4cSFlorian Wechsung     }
3357cb87ef4cSFlorian Wechsung   }
3358cb87ef4cSFlorian Wechsung 
33597407ba93SFlorian Wechsung   /* Let's see how significant the influences of the previous fixing up step was.*/
33605dc86ac1SFlorian Wechsung   if (viewer) {
3361125d2a8fSFlorian Wechsung     ierr = PetscViewerASCIIPrintf(viewer, "After.       ");CHKERRQ(ierr);
3362125d2a8fSFlorian Wechsung     ierr = DMPlexViewDistribution(comm, cumSumVertices[rank+1]-cumSumVertices[rank], ncon, vtxwgt, part, viewer);CHKERRQ(ierr);
33637407ba93SFlorian Wechsung   }
33647407ba93SFlorian Wechsung 
33655dc86ac1SFlorian Wechsung   ierr = PetscLayoutDestroy(&layout);CHKERRQ(ierr);
3366cb87ef4cSFlorian Wechsung   ierr = PetscFree(xadj);CHKERRQ(ierr);
3367cb87ef4cSFlorian Wechsung   ierr = PetscFree(adjncy);CHKERRQ(ierr);
336841525646SFlorian Wechsung   ierr = PetscFree(vtxwgt);CHKERRQ(ierr);
3369cb87ef4cSFlorian Wechsung 
33707f57c1a4SFlorian Wechsung   /* Almost done, now rewrite the SF to reflect the new ownership. */
3371cf818975SFlorian Wechsung   {
33727f57c1a4SFlorian Wechsung     PetscInt *pointsToRewrite;
337306b3913eSFlorian Wechsung     ierr = PetscMalloc1(numNonExclusivelyOwned, &pointsToRewrite);CHKERRQ(ierr);
33747f57c1a4SFlorian Wechsung     counter = 0;
3375cb87ef4cSFlorian Wechsung     for(i=0; i<pEnd-pStart; i++) {
3376cb87ef4cSFlorian Wechsung       if (toBalance[i]) {
3377cb87ef4cSFlorian Wechsung         if (isNonExclusivelyOwned[i]) {
33787f57c1a4SFlorian Wechsung           pointsToRewrite[counter] = i + pStart;
3379cb87ef4cSFlorian Wechsung           counter++;
3380cb87ef4cSFlorian Wechsung         }
3381cb87ef4cSFlorian Wechsung       }
3382cb87ef4cSFlorian Wechsung     }
33837f57c1a4SFlorian Wechsung     ierr = DMPlexRewriteSF(dm, numNonExclusivelyOwned, pointsToRewrite, part+1, degrees);CHKERRQ(ierr);
33847f57c1a4SFlorian Wechsung     ierr = PetscFree(pointsToRewrite);CHKERRQ(ierr);
3385cf818975SFlorian Wechsung   }
3386cb87ef4cSFlorian Wechsung 
3387cb87ef4cSFlorian Wechsung   ierr = PetscFree(toBalance);CHKERRQ(ierr);
3388cb87ef4cSFlorian Wechsung   ierr = PetscFree(isLeaf);CHKERRQ(ierr);
3389cf818975SFlorian Wechsung   ierr = PetscFree(isNonExclusivelyOwned);CHKERRQ(ierr);
3390cf818975SFlorian Wechsung   ierr = PetscFree(isExclusivelyOwned);CHKERRQ(ierr);
33917f57c1a4SFlorian Wechsung   ierr = PetscFree(part);CHKERRQ(ierr);
33925dc86ac1SFlorian Wechsung   if (viewer) {
339306b3913eSFlorian Wechsung     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
339406b3913eSFlorian Wechsung     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
33957d197802SFlorian Wechsung   }
33968b879b41SFlorian Wechsung   if (success) *success = PETSC_TRUE;
339741525646SFlorian Wechsung   ierr = PetscLogEventEnd(DMPLEX_RebalanceSharedPoints, dm, 0, 0, 0);CHKERRQ(ierr);
3398240408d3SFlorian Wechsung #else
33995f441e9bSFlorian Wechsung   SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
340041525646SFlorian Wechsung #endif
3401cb87ef4cSFlorian Wechsung   PetscFunctionReturn(0);
3402cb87ef4cSFlorian Wechsung }
3403