#include /*I "petscdmplex.h" I*/ PetscClassId PETSCPARTITIONER_CLASSID = 0; PetscFunctionList PetscPartitionerList = NULL; PetscBool PetscPartitionerRegisterAllCalled = PETSC_FALSE; PetscBool ChacoPartitionercite = PETSC_FALSE; const char ChacoPartitionerCitation[] = "@inproceedings{Chaco95,\n" " author = {Bruce Hendrickson and Robert Leland},\n" " title = {A multilevel algorithm for partitioning graphs},\n" " booktitle = {Supercomputing '95: Proceedings of the 1995 ACM/IEEE Conference on Supercomputing (CDROM)}," " isbn = {0-89791-816-9},\n" " pages = {28},\n" " doi = {http://doi.acm.org/10.1145/224170.224228},\n" " publisher = {ACM Press},\n" " address = {New York},\n" " year = {1995}\n}\n"; PetscBool ParMetisPartitionercite = PETSC_FALSE; const char ParMetisPartitionerCitation[] = "@article{KarypisKumar98,\n" " author = {George Karypis and Vipin Kumar},\n" " title = {A Parallel Algorithm for Multilevel Graph Partitioning and Sparse Matrix Ordering},\n" " journal = {Journal of Parallel and Distributed Computing},\n" " volume = {48},\n" " pages = {71--85},\n" " year = {1998}\n}\n"; #undef __FUNCT__ #define __FUNCT__ "DMPlexCreateNeighborCSR" PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency) { const PetscInt maxFaceCases = 30; PetscInt numFaceCases = 0; PetscInt numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */ PetscInt *off, *adj; PetscInt *neighborCells = NULL; PetscInt dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell; PetscErrorCode ierr; PetscFunctionBegin; /* For parallel partitioning, I think you have to communicate supports */ ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); cellDim = dim - cellHeight; ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); if (cEnd - cStart == 0) { if (numVertices) *numVertices = 0; if (offsets) *offsets = NULL; if (adjacency) *adjacency = NULL; PetscFunctionReturn(0); } numCells = cEnd - cStart; faceDepth = depth - cellHeight; if (dim == depth) { PetscInt f, fStart, fEnd; ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr); /* Count neighboring cells */ ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr); for (f = fStart; f < fEnd; ++f) { const PetscInt *support; PetscInt supportSize; ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr); ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr); if (supportSize == 2) { PetscInt numChildren; ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr); if (!numChildren) { ++off[support[0]-cStart+1]; ++off[support[1]-cStart+1]; } } } /* Prefix sum */ for (c = 1; c <= numCells; ++c) off[c] += off[c-1]; if (adjacency) { PetscInt *tmp; ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr); ierr = PetscMalloc1(numCells+1, &tmp);CHKERRQ(ierr); ierr = PetscMemcpy(tmp, off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr); /* Get neighboring cells */ for (f = fStart; f < fEnd; ++f) { const PetscInt *support; PetscInt supportSize; ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr); ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr); if (supportSize == 2) { PetscInt numChildren; ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr); if (!numChildren) { adj[tmp[support[0]-cStart]++] = support[1]; adj[tmp[support[1]-cStart]++] = support[0]; } } } #if defined(PETSC_USE_DEBUG) 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); #endif ierr = PetscFree(tmp);CHKERRQ(ierr); } if (numVertices) *numVertices = numCells; if (offsets) *offsets = off; if (adjacency) *adjacency = adj; PetscFunctionReturn(0); } /* Setup face recognition */ if (faceDepth == 1) { 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 */ for (c = cStart; c < cEnd; ++c) { PetscInt corners; ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr); if (!cornersSeen[corners]) { PetscInt nFV; if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases"); cornersSeen[corners] = 1; ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr); numFaceVertices[numFaceCases++] = nFV; } } } ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr); /* Count neighboring cells */ for (cell = cStart; cell < cEnd; ++cell) { PetscInt numNeighbors = PETSC_DETERMINE, n; ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr); /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */ for (n = 0; n < numNeighbors; ++n) { PetscInt cellPair[2]; PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE; PetscInt meetSize = 0; const PetscInt *meet = NULL; cellPair[0] = cell; cellPair[1] = neighborCells[n]; if (cellPair[0] == cellPair[1]) continue; if (!found) { ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); if (meetSize) { PetscInt f; for (f = 0; f < numFaceCases; ++f) { if (numFaceVertices[f] == meetSize) { found = PETSC_TRUE; break; } } } ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); } if (found) ++off[cell-cStart+1]; } } /* Prefix sum */ for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1]; if (adjacency) { ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr); /* Get neighboring cells */ for (cell = cStart; cell < cEnd; ++cell) { PetscInt numNeighbors = PETSC_DETERMINE, n; PetscInt cellOffset = 0; ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr); /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */ for (n = 0; n < numNeighbors; ++n) { PetscInt cellPair[2]; PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE; PetscInt meetSize = 0; const PetscInt *meet = NULL; cellPair[0] = cell; cellPair[1] = neighborCells[n]; if (cellPair[0] == cellPair[1]) continue; if (!found) { ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); if (meetSize) { PetscInt f; for (f = 0; f < numFaceCases; ++f) { if (numFaceVertices[f] == meetSize) { found = PETSC_TRUE; break; } } } ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); } if (found) { adj[off[cell-cStart]+cellOffset] = neighborCells[n]; ++cellOffset; } } } } ierr = PetscFree(neighborCells);CHKERRQ(ierr); if (numVertices) *numVertices = numCells; if (offsets) *offsets = off; if (adjacency) *adjacency = adj; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexEnlargePartition" /* Expand the partition by BFS on the adjacency graph */ PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection partSection, IS *partition) { PetscHashI h; const PetscInt *points; PetscInt **tmpPoints, *newPoints, totPoints = 0; PetscInt pStart, pEnd, part, q; PetscBool useCone; PetscErrorCode ierr; PetscFunctionBegin; PetscHashICreate(h); ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr); ierr = PetscSectionSetChart(partSection, pStart, pEnd);CHKERRQ(ierr); ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr); ierr = PetscMalloc1(pEnd - pStart, &tmpPoints);CHKERRQ(ierr); ierr = DMPlexGetAdjacencyUseCone(dm, &useCone);CHKERRQ(ierr); ierr = DMPlexSetAdjacencyUseCone(dm, PETSC_TRUE);CHKERRQ(ierr); for (part = pStart; part < pEnd; ++part) { PetscInt *adj = NULL; PetscInt numPoints, nP, numNewPoints, off, p, n = 0; PetscHashIClear(h); ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr); ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr); /* Add all existing points to h */ for (p = 0; p < numPoints; ++p) { const PetscInt point = points[off+p]; PetscHashIAdd(h, point, 1); } PetscHashISize(h, nP); if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP); /* Add all points in next BFS level */ for (p = 0; p < numPoints; ++p) { const PetscInt point = points[off+p]; PetscInt adjSize = PETSC_DETERMINE, a; ierr = DMPlexGetAdjacency(dm, point, &adjSize, &adj);CHKERRQ(ierr); for (a = 0; a < adjSize; ++a) PetscHashIAdd(h, adj[a], 1); } PetscHashISize(h, numNewPoints); ierr = PetscSectionSetDof(partSection, part, numNewPoints);CHKERRQ(ierr); ierr = PetscMalloc1(numNewPoints, &tmpPoints[part]);CHKERRQ(ierr); ierr = PetscHashIGetKeys(h, &n, tmpPoints[part]);CHKERRQ(ierr); ierr = PetscFree(adj);CHKERRQ(ierr); totPoints += numNewPoints; } ierr = DMPlexSetAdjacencyUseCone(dm, useCone);CHKERRQ(ierr); ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr); PetscHashIDestroy(h); ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); ierr = PetscMalloc1(totPoints, &newPoints);CHKERRQ(ierr); for (part = pStart, q = 0; part < pEnd; ++part) { PetscInt numPoints, p; ierr = PetscSectionGetDof(partSection, part, &numPoints);CHKERRQ(ierr); for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p]; ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr); } ierr = PetscFree(tmpPoints);CHKERRQ(ierr); ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerRegister" /*@C PetscPartitionerRegister - Adds a new PetscPartitioner implementation Not Collective Input Parameters: + name - The name of a new user-defined creation routine - create_func - The creation routine itself Notes: PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners Sample usage: .vb PetscPartitionerRegister("my_part", MyPetscPartitionerCreate); .ve Then, your PetscPartitioner type can be chosen with the procedural interface via .vb PetscPartitionerCreate(MPI_Comm, PetscPartitioner *); PetscPartitionerSetType(PetscPartitioner, "my_part"); .ve or at runtime via the option .vb -petscpartitioner_type my_part .ve Level: advanced .keywords: PetscPartitioner, register .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy() @*/ PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner)) { PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerSetType" /*@C PetscPartitionerSetType - Builds a particular PetscPartitioner Collective on PetscPartitioner Input Parameters: + part - The PetscPartitioner object - name - The kind of partitioner Options Database Key: . -petscpartitioner_type - Sets the PetscPartitioner type; use -help for a list of available types Level: intermediate .keywords: PetscPartitioner, set, type .seealso: PetscPartitionerGetType(), PetscPartitionerCreate() @*/ PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name) { PetscErrorCode (*r)(PetscPartitioner); PetscBool match; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr); if (match) PetscFunctionReturn(0); ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr); ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr); if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name); if (part->ops->destroy) { ierr = (*part->ops->destroy)(part);CHKERRQ(ierr); part->ops->destroy = NULL; } ierr = (*r)(part);CHKERRQ(ierr); ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerGetType" /*@C PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object. Not Collective Input Parameter: . part - The PetscPartitioner Output Parameter: . name - The PetscPartitioner type name Level: intermediate .keywords: PetscPartitioner, get, type, name .seealso: PetscPartitionerSetType(), PetscPartitionerCreate() @*/ PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); PetscValidPointer(name, 2); ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr); *name = ((PetscObject) part)->type_name; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerView" /*@C PetscPartitionerView - Views a PetscPartitioner Collective on PetscPartitioner Input Parameter: + part - the PetscPartitioner object to view - v - the viewer Level: developer .seealso: PetscPartitionerDestroy() @*/ PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);} if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerViewFromOptions" /* PetscPartitionerViewFromOptions - Processes command line options to determine if/how a PetscPartitioner is to be viewed. Collective on PetscPartitioner Input Parameters: + part - the PetscPartitioner . prefix - prefix to use for viewing, or NULL - optionname - option to activate viewing Level: intermediate .keywords: PetscPartitioner, view, options, database .seealso: VecViewFromOptions(), MatViewFromOptions() */ PetscErrorCode PetscPartitionerViewFromOptions(PetscPartitioner part, const char prefix[], const char optionname[]) { PetscViewer viewer; PetscViewerFormat format; PetscBool flg; PetscErrorCode ierr; PetscFunctionBegin; if (prefix) {ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) part), prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr);} else {ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) part), ((PetscObject) part)->prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr);} if (flg) { ierr = PetscViewerPushFormat(viewer, format);CHKERRQ(ierr); ierr = PetscPartitionerView(part, viewer);CHKERRQ(ierr); ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); } PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerSetTypeFromOptions_Internal" PetscErrorCode PetscPartitionerSetTypeFromOptions_Internal(PetscPartitioner part) { const char *defaultType; char name[256]; PetscBool flg; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); if (!((PetscObject) part)->type_name) defaultType = PETSCPARTITIONERCHACO; else defaultType = ((PetscObject) part)->type_name; ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr); ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr); ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, 256, &flg);CHKERRQ(ierr); if (flg) { ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr); } else if (!((PetscObject) part)->type_name) { ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr); } ierr = PetscOptionsEnd();CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerSetFromOptions" /*@ PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database Collective on PetscPartitioner Input Parameter: . part - the PetscPartitioner object to set options for Level: developer .seealso: PetscPartitionerView() @*/ PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); ierr = PetscPartitionerSetTypeFromOptions_Internal(part);CHKERRQ(ierr); ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr); if (part->ops->setfromoptions) {ierr = (*part->ops->setfromoptions)(part);CHKERRQ(ierr);} /* process any options handlers added with PetscObjectAddOptionsHandler() */ ierr = PetscObjectProcessOptionsHandlers((PetscObject) part);CHKERRQ(ierr); ierr = PetscOptionsEnd();CHKERRQ(ierr); ierr = PetscPartitionerViewFromOptions(part, NULL, "-petscpartitioner_view");CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerSetUp" /*@C PetscPartitionerSetUp - Construct data structures for the PetscPartitioner Collective on PetscPartitioner Input Parameter: . part - the PetscPartitioner object to setup Level: developer .seealso: PetscPartitionerView(), PetscPartitionerDestroy() @*/ PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part) { PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerDestroy" /*@ PetscPartitionerDestroy - Destroys a PetscPartitioner object Collective on PetscPartitioner Input Parameter: . part - the PetscPartitioner object to destroy Level: developer .seealso: PetscPartitionerView() @*/ PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part) { PetscErrorCode ierr; PetscFunctionBegin; if (!*part) PetscFunctionReturn(0); PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1); if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);} ((PetscObject) (*part))->refct = 0; if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);} ierr = PetscHeaderDestroy(part);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerCreate" /*@ PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType(). Collective on MPI_Comm Input Parameter: . comm - The communicator for the PetscPartitioner object Output Parameter: . part - The PetscPartitioner object Level: beginner .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL @*/ PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part) { PetscPartitioner p; PetscErrorCode ierr; PetscFunctionBegin; PetscValidPointer(part, 2); *part = NULL; ierr = PetscFVInitializePackage();CHKERRQ(ierr); ierr = PetscHeaderCreate(p, _p_PetscPartitioner, struct _PetscPartitionerOps, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr); ierr = PetscMemzero(p->ops, sizeof(struct _PetscPartitionerOps));CHKERRQ(ierr); *part = p; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerPartition" /*@ PetscPartitionerPartition - Create a non-overlapping partition of the cells in the mesh Collective on DM Input Parameters: + part - The PetscPartitioner . dm - The mesh DM - enlarge - Expand each partition with neighbors Output Parameters: + partSection - The PetscSection giving the division of points by partition . partition - The list of points by partition . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL Note: Instead of cells, points at a given height can be partitioned by calling PetscPartitionerSetPointHeight() Level: developer .seealso DMPlexDistribute(), PetscPartitionerSetPointHeight(), PetscPartitionerCreate() @*/ PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, DM dm, PetscBool enlarge, PetscSection partSection, IS *partition, PetscSection origPartSection, IS *origPartition) { PetscMPIInt size; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); PetscValidHeaderSpecific(dm, DM_CLASSID, 2); PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4); PetscValidPointer(partition, 5); if (enlarge) {PetscValidHeaderSpecific(origPartSection, PETSC_SECTION_CLASSID, 6);} if (enlarge) {PetscValidPointer(origPartition, 7);} ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr); if (origPartition) *origPartition = NULL; if (size == 1) { PetscInt *points; PetscInt cStart, cEnd, c; ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr); ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr); ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr); ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr); for (c = cStart; c < cEnd; ++c) points[c] = c; ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); PetscFunctionReturn(0); } if (part->height == 0) { PetscInt numVertices; PetscInt *start = NULL; PetscInt *adjacency = NULL; ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr); if (!part->ops->partition) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONGSTATE, "PetscPartitioner has no type"); ierr = (*part->ops->partition)(part, dm, size, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr); if (enlarge) { origPartSection = partSection; *origPartition = *partition; ierr = DMPlexEnlargePartition(dm, start, adjacency, origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr); } ierr = PetscFree(start);CHKERRQ(ierr); ierr = PetscFree(adjacency);CHKERRQ(ierr); } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerDestroy_Shell" PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part) { PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr); ierr = ISDestroy(&p->partition);CHKERRQ(ierr); ierr = PetscFree(p);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerView_Shell_Ascii" PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer) { PetscViewerFormat format; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer, "Shell Graph Partitioner:\n");CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerView_Shell" PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer) { PetscBool iascii; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);} PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerPartition_Shell" PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) { PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; PetscInt np; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr); if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np); ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr); if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np); ierr = PetscSectionCopy(p->section, partSection);CHKERRQ(ierr); *partition = p->partition; ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerInitialize_Shell" PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part) { PetscFunctionBegin; part->ops->view = PetscPartitionerView_Shell; part->ops->destroy = PetscPartitionerDestroy_Shell; part->ops->partition = PetscPartitionerPartition_Shell; PetscFunctionReturn(0); } /*MC PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object Level: intermediate .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() M*/ #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerCreate_Shell" PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part) { PetscPartitioner_Shell *p; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); ierr = PetscNewLog(part, &p);CHKERRQ(ierr); part->data = p; ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerShellSetPartition" /*@C PetscPartitionerShellSetPartition - Set an artifical partition for a mesh Collective on PART Input Parameters: + part - The PetscPartitioner . numProcs - The number of partitions . sizes - array of size numProcs (or NULL) providing the number of points in each partition - points - array of size sum(sizes) (may be NULL iff sizes is NULL) providing the partition each point belongs to Level: developer Notes: It is safe to free the sizes and points arrays after use in this routine. .seealso DMPlexDistribute(), PetscPartitionerCreate() @*/ PetscErrorCode PetscPartitionerShellSetPartition(PetscPartitioner part, PetscInt numProcs, const PetscInt sizes[], const PetscInt points[]) { PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; PetscInt proc, numPoints; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); if (sizes) {PetscValidPointer(sizes, 3);} if (sizes) {PetscValidPointer(points, 4);} ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr); ierr = ISDestroy(&p->partition);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject) part), &p->section);CHKERRQ(ierr); ierr = PetscSectionSetChart(p->section, 0, numProcs);CHKERRQ(ierr); if (sizes) { for (proc = 0; proc < numProcs; ++proc) { ierr = PetscSectionSetDof(p->section, proc, sizes[proc]);CHKERRQ(ierr); } } ierr = PetscSectionSetUp(p->section);CHKERRQ(ierr); ierr = PetscSectionGetStorageSize(p->section, &numPoints);CHKERRQ(ierr); ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), numPoints, points, PETSC_COPY_VALUES, &p->partition);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerDestroy_Chaco" PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part) { PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscFree(p);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerView_Chaco_Ascii" PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer) { PetscViewerFormat format; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer, "Chaco Graph Partitioner:\n");CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerView_Chaco" PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer) { PetscBool iascii; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);} PetscFunctionReturn(0); } #if defined(PETSC_HAVE_CHACO) #if defined(PETSC_HAVE_UNISTD_H) #include #endif /* Chaco does not have an include file */ PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts, float *ewgts, float *x, float *y, float *z, char *outassignname, char *outfilename, short *assignment, int architecture, int ndims_tot, int mesh_dims[3], double *goal, int global_method, int local_method, int rqi_flag, int vmax, int ndims, double eigtol, long seed); extern int FREE_GRAPH; #endif #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerPartition_Chaco" PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) { #if defined(PETSC_HAVE_CHACO) enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3}; MPI_Comm comm; int nvtxs = numVertices; /* number of vertices in full graph */ int *vwgts = NULL; /* weights for all vertices */ float *ewgts = NULL; /* weights for all edges */ float *x = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */ char *outassignname = NULL; /* name of assignment output file */ char *outfilename = NULL; /* output file name */ int architecture = 1; /* 0 => hypercube, d => d-dimensional mesh */ int ndims_tot = 0; /* total number of cube dimensions to divide */ int mesh_dims[3]; /* dimensions of mesh of processors */ double *goal = NULL; /* desired set sizes for each set */ int global_method = 1; /* global partitioning algorithm */ int local_method = 1; /* local partitioning algorithm */ int rqi_flag = 0; /* should I use RQI/Symmlq eigensolver? */ int vmax = 200; /* how many vertices to coarsen down to? */ int ndims = 1; /* number of eigenvectors (2^d sets) */ double eigtol = 0.001; /* tolerance on eigenvectors */ long seed = 123636512; /* for random graph mutations */ short int *assignment; /* Output partition */ int fd_stdout, fd_pipe[2]; PetscInt *points; int i, v, p; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); if (!numVertices) { ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); PetscFunctionReturn(0); } FREE_GRAPH = 0; /* Do not let Chaco free my memory */ for (i = 0; i < start[numVertices]; ++i) ++adjacency[i]; if (global_method == INERTIAL_METHOD) { /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */ SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported"); } mesh_dims[0] = nparts; mesh_dims[1] = 1; mesh_dims[2] = 1; ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr); /* Chaco outputs to stdout. We redirect this to a buffer. */ /* TODO: check error codes for UNIX calls */ #if defined(PETSC_HAVE_UNISTD_H) { int piperet; piperet = pipe(fd_pipe); if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe"); fd_stdout = dup(1); close(1); dup2(fd_pipe[1], 1); } #endif ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename, assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag, vmax, ndims, eigtol, seed); #if defined(PETSC_HAVE_UNISTD_H) { char msgLog[10000]; int count; fflush(stdout); count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char)); if (count < 0) count = 0; msgLog[count] = 0; close(1); dup2(fd_stdout, 1); close(fd_stdout); close(fd_pipe[0]); close(fd_pipe[1]); if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog); } #endif /* Convert to PetscSection+IS */ ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); for (v = 0; v < nvtxs; ++v) { ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr); } ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr); for (p = 0, i = 0; p < nparts; ++p) { for (v = 0; v < nvtxs; ++v) { if (assignment[v] == p) points[i++] = v; } } if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs); ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); if (global_method == INERTIAL_METHOD) { /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */ } ierr = PetscFree(assignment);CHKERRQ(ierr); for (i = 0; i < start[numVertices]; ++i) --adjacency[i]; PetscFunctionReturn(0); #else SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco."); #endif } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerInitialize_Chaco" PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part) { PetscFunctionBegin; part->ops->view = PetscPartitionerView_Chaco; part->ops->destroy = PetscPartitionerDestroy_Chaco; part->ops->partition = PetscPartitionerPartition_Chaco; PetscFunctionReturn(0); } /*MC PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library Level: intermediate .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() M*/ #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerCreate_Chaco" PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part) { PetscPartitioner_Chaco *p; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); ierr = PetscNewLog(part, &p);CHKERRQ(ierr); part->data = p; ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr); ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerDestroy_ParMetis" PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part) { PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscFree(p);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerView_ParMetis_Ascii" PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer) { PetscViewerFormat format; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); ierr = PetscViewerASCIIPrintf(viewer, "ParMetis Graph Partitioner:\n");CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerView_ParMetis" PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer) { PetscBool iascii; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);} PetscFunctionReturn(0); } #if defined(PETSC_HAVE_PARMETIS) #include #endif #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerPartition_ParMetis" PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) { #if defined(PETSC_HAVE_PARMETIS) MPI_Comm comm; PetscInt nvtxs = numVertices; /* The number of vertices in full graph */ PetscInt *vtxdist; /* Distribution of vertices across processes */ PetscInt *xadj = start; /* Start of edge list for each vertex */ PetscInt *adjncy = adjacency; /* Edge lists for all vertices */ PetscInt *vwgt = NULL; /* Vertex weights */ PetscInt *adjwgt = NULL; /* Edge weights */ PetscInt wgtflag = 0; /* Indicates which weights are present */ PetscInt numflag = 0; /* Indicates initial offset (0 or 1) */ PetscInt ncon = 1; /* The number of weights per vertex */ PetscReal *tpwgts; /* The fraction of vertex weights assigned to each partition */ PetscReal *ubvec; /* The balance intolerance for vertex weights */ PetscInt options[5]; /* Options */ /* Outputs */ PetscInt edgeCut; /* The number of edges cut by the partition */ PetscInt *assignment, *points; PetscMPIInt rank, p, v, i; PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr); ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); options[0] = 0; /* Use all defaults */ /* Calculate vertex distribution */ ierr = PetscMalloc4(nparts+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment);CHKERRQ(ierr); vtxdist[0] = 0; ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr); for (p = 2; p <= nparts; ++p) { vtxdist[p] += vtxdist[p-1]; } /* Calculate weights */ for (p = 0; p < nparts; ++p) { tpwgts[p] = 1.0/nparts; } ubvec[0] = 1.05; if (nparts == 1) { ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt)); } else { if (vtxdist[1] == vtxdist[nparts]) { if (!rank) { PetscStackPush("METIS_PartGraphKway"); ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment); PetscStackPop; if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()"); } } else { PetscStackPush("ParMETIS_V3_PartKway"); ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm); PetscStackPop; if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()"); } } /* Convert to PetscSection+IS */ ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);} ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr); for (p = 0, i = 0; p < nparts; ++p) { for (v = 0; v < nvtxs; ++v) { if (assignment[v] == p) points[i++] = v; } } if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs); ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); ierr = PetscFree4(vtxdist,tpwgts,ubvec,assignment);CHKERRQ(ierr); #else SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis."); #endif PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerInitialize_ParMetis" PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part) { PetscFunctionBegin; part->ops->view = PetscPartitionerView_ParMetis; part->ops->destroy = PetscPartitionerDestroy_ParMetis; part->ops->partition = PetscPartitionerPartition_ParMetis; PetscFunctionReturn(0); } /*MC PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMetis library Level: intermediate .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() M*/ #undef __FUNCT__ #define __FUNCT__ "PetscPartitionerCreate_ParMetis" PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part) { PetscPartitioner_ParMetis *p; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); ierr = PetscNewLog(part, &p);CHKERRQ(ierr); part->data = p; ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr); ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexGetPartitioner" /*@ DMPlexGetPartitioner - Get the mesh partitioner Not collective Input Parameter: . dm - The DM Output Parameter: . part - The PetscPartitioner Level: developer Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner. .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerCreate() @*/ PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part) { DM_Plex *mesh = (DM_Plex *) dm->data; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscValidPointer(part, 2); *part = mesh->partitioner; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexSetPartitioner" /*@ DMPlexSetPartitioner - Set the mesh partitioner logically collective on dm and part Input Parameters: + dm - The DM - part - The partitioner Level: developer Note: Any existing PetscPartitioner will be destroyed. .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate() @*/ PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part) { DM_Plex *mesh = (DM_Plex *) dm->data; PetscErrorCode ierr; PetscFunctionBegin; PetscValidHeaderSpecific(dm, DM_CLASSID, 1); PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2); ierr = PetscObjectReference((PetscObject)part);CHKERRQ(ierr); ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr); mesh->partitioner = part; PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexMarkTreeClosure" static PetscErrorCode DMPlexMarkTreeClosure(DM dm, PetscSegBuffer segpart, PetscBT bt, PetscInt point, PetscInt *partSize) { PetscInt parent, closureSize, *closure = NULL, i, pStart, pEnd; PetscErrorCode ierr; PetscFunctionBegin; ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr); if (parent == point) PetscFunctionReturn(0); ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); for (i = 0; i < closureSize; i++) { PetscInt cpoint = closure[2*i]; if (!PetscBTLookupSet(bt,cpoint-pStart)) { PetscInt *PETSC_RESTRICT pt; (*partSize)++; ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr); *pt = cpoint; } ierr = DMPlexMarkTreeClosure(dm,segpart,bt,cpoint,partSize);CHKERRQ(ierr); } ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); PetscFunctionReturn(0); } #undef __FUNCT__ #define __FUNCT__ "DMPlexCreatePartitionClosure" PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition) { /* const PetscInt height = 0; */ const PetscInt *partArray; PetscInt *allPoints, *packPoints; PetscInt rStart, rEnd, rank, pStart, pEnd, newSize; PetscErrorCode ierr; PetscBT bt; PetscSegBuffer segpack,segpart; PetscFunctionBegin; ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr); ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr); ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr); ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr); ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr); ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr); ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr); for (rank = rStart; rank < rEnd; ++rank) { PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints; ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr); ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr); for (p = 0; p < numPoints; ++p) { PetscInt point = partArray[offset+p], closureSize, c; PetscInt *closure = NULL; /* TODO Include support for height > 0 case */ ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); for (c=0; c