1 #include <petsc/private/dmpleximpl.h> /*I "petscdmplex.h" I*/ 2 3 PetscClassId PETSCPARTITIONER_CLASSID = 0; 4 5 PetscFunctionList PetscPartitionerList = NULL; 6 PetscBool PetscPartitionerRegisterAllCalled = PETSC_FALSE; 7 8 PetscBool ChacoPartitionercite = PETSC_FALSE; 9 const char ChacoPartitionerCitation[] = "@inproceedings{Chaco95,\n" 10 " author = {Bruce Hendrickson and Robert Leland},\n" 11 " title = {A multilevel algorithm for partitioning graphs},\n" 12 " booktitle = {Supercomputing '95: Proceedings of the 1995 ACM/IEEE Conference on Supercomputing (CDROM)}," 13 " isbn = {0-89791-816-9},\n" 14 " pages = {28},\n" 15 " doi = {http://doi.acm.org/10.1145/224170.224228},\n" 16 " publisher = {ACM Press},\n" 17 " address = {New York},\n" 18 " year = {1995}\n}\n"; 19 20 PetscBool ParMetisPartitionercite = PETSC_FALSE; 21 const char ParMetisPartitionerCitation[] = "@article{KarypisKumar98,\n" 22 " author = {George Karypis and Vipin Kumar},\n" 23 " title = {A Parallel Algorithm for Multilevel Graph Partitioning and Sparse Matrix Ordering},\n" 24 " journal = {Journal of Parallel and Distributed Computing},\n" 25 " volume = {48},\n" 26 " pages = {71--85},\n" 27 " year = {1998}\n}\n"; 28 29 /*@C 30 DMPlexCreatePartitionerGraph - Create a CSR graph of point connections for the partitioner 31 32 Input Parameters: 33 + dm - The mesh DM dm 34 - height - Height of the strata from which to construct the graph 35 36 Output Parameter: 37 + numVertices - Number of vertices in the graph 38 . offsets - Point offsets in the graph 39 . adjacency - Point connectivity in the graph 40 - 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. 41 42 The user can control the definition of adjacency for the mesh using DMPlexGetAdjacencyUseCone() and 43 DMPlexSetAdjacencyUseClosure(). They should choose the combination appropriate for the function 44 representation on the mesh. 45 46 Level: developer 47 48 .seealso: PetscPartitionerGetType(), PetscPartitionerCreate(), DMPlexSetAdjacencyUseCone(), DMPlexSetAdjacencyUseClosure() 49 @*/ 50 PetscErrorCode DMPlexCreatePartitionerGraph(DM dm, PetscInt height, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency, IS *globalNumbering) 51 { 52 PetscInt p, pStart, pEnd, a, adjSize, idx, size, nroots; 53 PetscInt *adj = NULL, *vOffsets = NULL, *graph = NULL; 54 IS cellNumbering; 55 const PetscInt *cellNum; 56 PetscBool useCone, useClosure; 57 PetscSection section; 58 PetscSegBuffer adjBuffer; 59 PetscSF sfPoint; 60 PetscMPIInt rank; 61 PetscErrorCode ierr; 62 63 PetscFunctionBegin; 64 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr); 65 ierr = DMPlexGetHeightStratum(dm, height, &pStart, &pEnd);CHKERRQ(ierr); 66 ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr); 67 ierr = PetscSFGetGraph(sfPoint, &nroots, NULL, NULL, NULL);CHKERRQ(ierr); 68 /* Build adjacency graph via a section/segbuffer */ 69 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), §ion);CHKERRQ(ierr); 70 ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr); 71 ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&adjBuffer);CHKERRQ(ierr); 72 /* Always use FVM adjacency to create partitioner graph */ 73 ierr = DMPlexGetAdjacencyUseCone(dm, &useCone);CHKERRQ(ierr); 74 ierr = DMPlexGetAdjacencyUseClosure(dm, &useClosure);CHKERRQ(ierr); 75 ierr = DMPlexSetAdjacencyUseCone(dm, PETSC_TRUE);CHKERRQ(ierr); 76 ierr = DMPlexSetAdjacencyUseClosure(dm, PETSC_FALSE);CHKERRQ(ierr); 77 ierr = DMPlexCreateCellNumbering_Internal(dm, PETSC_TRUE, &cellNumbering);CHKERRQ(ierr); 78 if (globalNumbering) { 79 ierr = PetscObjectReference((PetscObject)cellNumbering);CHKERRQ(ierr); 80 *globalNumbering = cellNumbering; 81 } 82 ierr = ISGetIndices(cellNumbering, &cellNum);CHKERRQ(ierr); 83 for (*numVertices = 0, p = pStart; p < pEnd; p++) { 84 /* Skip non-owned cells in parallel (ParMetis expects no overlap) */ 85 if (nroots > 0) {if (cellNum[p] < 0) continue;} 86 adjSize = PETSC_DETERMINE; 87 ierr = DMPlexGetAdjacency(dm, p, &adjSize, &adj);CHKERRQ(ierr); 88 for (a = 0; a < adjSize; ++a) { 89 const PetscInt point = adj[a]; 90 if (point != p && pStart <= point && point < pEnd) { 91 PetscInt *PETSC_RESTRICT pBuf; 92 ierr = PetscSectionAddDof(section, p, 1);CHKERRQ(ierr); 93 ierr = PetscSegBufferGetInts(adjBuffer, 1, &pBuf);CHKERRQ(ierr); 94 *pBuf = point; 95 } 96 } 97 (*numVertices)++; 98 } 99 ierr = DMPlexSetAdjacencyUseCone(dm, useCone);CHKERRQ(ierr); 100 ierr = DMPlexSetAdjacencyUseClosure(dm, useClosure);CHKERRQ(ierr); 101 /* Derive CSR graph from section/segbuffer */ 102 ierr = PetscSectionSetUp(section);CHKERRQ(ierr); 103 ierr = PetscSectionGetStorageSize(section, &size);CHKERRQ(ierr); 104 ierr = PetscMalloc1(*numVertices+1, &vOffsets);CHKERRQ(ierr); 105 for (idx = 0, p = pStart; p < pEnd; p++) { 106 if (nroots > 0) {if (cellNum[p] < 0) continue;} 107 ierr = PetscSectionGetOffset(section, p, &(vOffsets[idx++]));CHKERRQ(ierr); 108 } 109 vOffsets[*numVertices] = size; 110 if (offsets) *offsets = vOffsets; 111 ierr = PetscSegBufferExtractAlloc(adjBuffer, &graph);CHKERRQ(ierr); 112 { 113 ISLocalToGlobalMapping ltogCells; 114 PetscInt n, size, *cells_arr; 115 /* In parallel, apply a global cell numbering to the graph */ 116 ierr = ISRestoreIndices(cellNumbering, &cellNum);CHKERRQ(ierr); 117 ierr = ISLocalToGlobalMappingCreateIS(cellNumbering, <ogCells);CHKERRQ(ierr); 118 ierr = ISLocalToGlobalMappingGetSize(ltogCells, &size);CHKERRQ(ierr); 119 ierr = ISLocalToGlobalMappingGetIndices(ltogCells, (const PetscInt**)&cells_arr);CHKERRQ(ierr); 120 /* Convert to positive global cell numbers */ 121 for (n=0; n<size; n++) {if (cells_arr[n] < 0) cells_arr[n] = -(cells_arr[n]+1);} 122 ierr = ISLocalToGlobalMappingRestoreIndices(ltogCells, (const PetscInt**)&cells_arr);CHKERRQ(ierr); 123 ierr = ISLocalToGlobalMappingApplyBlock(ltogCells, vOffsets[*numVertices], graph, graph);CHKERRQ(ierr); 124 ierr = ISLocalToGlobalMappingDestroy(<ogCells);CHKERRQ(ierr); 125 ierr = ISDestroy(&cellNumbering);CHKERRQ(ierr); 126 } 127 if (adjacency) *adjacency = graph; 128 /* Clean up */ 129 ierr = PetscSegBufferDestroy(&adjBuffer);CHKERRQ(ierr); 130 ierr = PetscSectionDestroy(§ion);CHKERRQ(ierr); 131 ierr = PetscFree(adj);CHKERRQ(ierr); 132 PetscFunctionReturn(0); 133 } 134 135 /*@C 136 DMPlexCreateNeighborCSR - Create a mesh graph (cell-cell adjacency) in parallel CSR format. 137 138 Collective 139 140 Input Arguments: 141 + dm - The DMPlex 142 - cellHeight - The height of mesh points to treat as cells (default should be 0) 143 144 Output Arguments: 145 + numVertices - The number of local vertices in the graph, or cells in the mesh. 146 . offsets - The offset to the adjacency list for each cell 147 - adjacency - The adjacency list for all cells 148 149 Note: This is suitable for input to a mesh partitioner like ParMetis. 150 151 Level: advanced 152 153 .seealso: DMPlexCreate() 154 @*/ 155 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency) 156 { 157 const PetscInt maxFaceCases = 30; 158 PetscInt numFaceCases = 0; 159 PetscInt numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */ 160 PetscInt *off, *adj; 161 PetscInt *neighborCells = NULL; 162 PetscInt dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell; 163 PetscErrorCode ierr; 164 165 PetscFunctionBegin; 166 /* For parallel partitioning, I think you have to communicate supports */ 167 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 168 cellDim = dim - cellHeight; 169 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 170 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 171 if (cEnd - cStart == 0) { 172 if (numVertices) *numVertices = 0; 173 if (offsets) *offsets = NULL; 174 if (adjacency) *adjacency = NULL; 175 PetscFunctionReturn(0); 176 } 177 numCells = cEnd - cStart; 178 faceDepth = depth - cellHeight; 179 if (dim == depth) { 180 PetscInt f, fStart, fEnd; 181 182 ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr); 183 /* Count neighboring cells */ 184 ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr); 185 for (f = fStart; f < fEnd; ++f) { 186 const PetscInt *support; 187 PetscInt supportSize; 188 ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr); 189 ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr); 190 if (supportSize == 2) { 191 PetscInt numChildren; 192 193 ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr); 194 if (!numChildren) { 195 ++off[support[0]-cStart+1]; 196 ++off[support[1]-cStart+1]; 197 } 198 } 199 } 200 /* Prefix sum */ 201 for (c = 1; c <= numCells; ++c) off[c] += off[c-1]; 202 if (adjacency) { 203 PetscInt *tmp; 204 205 ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr); 206 ierr = PetscMalloc1(numCells+1, &tmp);CHKERRQ(ierr); 207 ierr = PetscMemcpy(tmp, off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr); 208 /* Get neighboring cells */ 209 for (f = fStart; f < fEnd; ++f) { 210 const PetscInt *support; 211 PetscInt supportSize; 212 ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr); 213 ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr); 214 if (supportSize == 2) { 215 PetscInt numChildren; 216 217 ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr); 218 if (!numChildren) { 219 adj[tmp[support[0]-cStart]++] = support[1]; 220 adj[tmp[support[1]-cStart]++] = support[0]; 221 } 222 } 223 } 224 #if defined(PETSC_USE_DEBUG) 225 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); 226 #endif 227 ierr = PetscFree(tmp);CHKERRQ(ierr); 228 } 229 if (numVertices) *numVertices = numCells; 230 if (offsets) *offsets = off; 231 if (adjacency) *adjacency = adj; 232 PetscFunctionReturn(0); 233 } 234 /* Setup face recognition */ 235 if (faceDepth == 1) { 236 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 */ 237 238 for (c = cStart; c < cEnd; ++c) { 239 PetscInt corners; 240 241 ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr); 242 if (!cornersSeen[corners]) { 243 PetscInt nFV; 244 245 if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases"); 246 cornersSeen[corners] = 1; 247 248 ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr); 249 250 numFaceVertices[numFaceCases++] = nFV; 251 } 252 } 253 } 254 ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr); 255 /* Count neighboring cells */ 256 for (cell = cStart; cell < cEnd; ++cell) { 257 PetscInt numNeighbors = PETSC_DETERMINE, n; 258 259 ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr); 260 /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */ 261 for (n = 0; n < numNeighbors; ++n) { 262 PetscInt cellPair[2]; 263 PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE; 264 PetscInt meetSize = 0; 265 const PetscInt *meet = NULL; 266 267 cellPair[0] = cell; cellPair[1] = neighborCells[n]; 268 if (cellPair[0] == cellPair[1]) continue; 269 if (!found) { 270 ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 271 if (meetSize) { 272 PetscInt f; 273 274 for (f = 0; f < numFaceCases; ++f) { 275 if (numFaceVertices[f] == meetSize) { 276 found = PETSC_TRUE; 277 break; 278 } 279 } 280 } 281 ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 282 } 283 if (found) ++off[cell-cStart+1]; 284 } 285 } 286 /* Prefix sum */ 287 for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1]; 288 289 if (adjacency) { 290 ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr); 291 /* Get neighboring cells */ 292 for (cell = cStart; cell < cEnd; ++cell) { 293 PetscInt numNeighbors = PETSC_DETERMINE, n; 294 PetscInt cellOffset = 0; 295 296 ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr); 297 /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */ 298 for (n = 0; n < numNeighbors; ++n) { 299 PetscInt cellPair[2]; 300 PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE; 301 PetscInt meetSize = 0; 302 const PetscInt *meet = NULL; 303 304 cellPair[0] = cell; cellPair[1] = neighborCells[n]; 305 if (cellPair[0] == cellPair[1]) continue; 306 if (!found) { 307 ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 308 if (meetSize) { 309 PetscInt f; 310 311 for (f = 0; f < numFaceCases; ++f) { 312 if (numFaceVertices[f] == meetSize) { 313 found = PETSC_TRUE; 314 break; 315 } 316 } 317 } 318 ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 319 } 320 if (found) { 321 adj[off[cell-cStart]+cellOffset] = neighborCells[n]; 322 ++cellOffset; 323 } 324 } 325 } 326 } 327 ierr = PetscFree(neighborCells);CHKERRQ(ierr); 328 if (numVertices) *numVertices = numCells; 329 if (offsets) *offsets = off; 330 if (adjacency) *adjacency = adj; 331 PetscFunctionReturn(0); 332 } 333 334 /*@C 335 PetscPartitionerRegister - Adds a new PetscPartitioner implementation 336 337 Not Collective 338 339 Input Parameters: 340 + name - The name of a new user-defined creation routine 341 - create_func - The creation routine itself 342 343 Notes: 344 PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners 345 346 Sample usage: 347 .vb 348 PetscPartitionerRegister("my_part", MyPetscPartitionerCreate); 349 .ve 350 351 Then, your PetscPartitioner type can be chosen with the procedural interface via 352 .vb 353 PetscPartitionerCreate(MPI_Comm, PetscPartitioner *); 354 PetscPartitionerSetType(PetscPartitioner, "my_part"); 355 .ve 356 or at runtime via the option 357 .vb 358 -petscpartitioner_type my_part 359 .ve 360 361 Level: advanced 362 363 .keywords: PetscPartitioner, register 364 .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy() 365 366 @*/ 367 PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner)) 368 { 369 PetscErrorCode ierr; 370 371 PetscFunctionBegin; 372 ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr); 373 PetscFunctionReturn(0); 374 } 375 376 /*@C 377 PetscPartitionerSetType - Builds a particular PetscPartitioner 378 379 Collective on PetscPartitioner 380 381 Input Parameters: 382 + part - The PetscPartitioner object 383 - name - The kind of partitioner 384 385 Options Database Key: 386 . -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types 387 388 Level: intermediate 389 390 .keywords: PetscPartitioner, set, type 391 .seealso: PetscPartitionerGetType(), PetscPartitionerCreate() 392 @*/ 393 PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name) 394 { 395 PetscErrorCode (*r)(PetscPartitioner); 396 PetscBool match; 397 PetscErrorCode ierr; 398 399 PetscFunctionBegin; 400 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 401 ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr); 402 if (match) PetscFunctionReturn(0); 403 404 ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr); 405 ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr); 406 if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name); 407 408 if (part->ops->destroy) { 409 ierr = (*part->ops->destroy)(part);CHKERRQ(ierr); 410 part->ops->destroy = NULL; 411 } 412 ierr = (*r)(part);CHKERRQ(ierr); 413 ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr); 414 PetscFunctionReturn(0); 415 } 416 417 /*@C 418 PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object. 419 420 Not Collective 421 422 Input Parameter: 423 . part - The PetscPartitioner 424 425 Output Parameter: 426 . name - The PetscPartitioner type name 427 428 Level: intermediate 429 430 .keywords: PetscPartitioner, get, type, name 431 .seealso: PetscPartitionerSetType(), PetscPartitionerCreate() 432 @*/ 433 PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name) 434 { 435 PetscErrorCode ierr; 436 437 PetscFunctionBegin; 438 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 439 PetscValidPointer(name, 2); 440 ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr); 441 *name = ((PetscObject) part)->type_name; 442 PetscFunctionReturn(0); 443 } 444 445 /*@C 446 PetscPartitionerView - Views a PetscPartitioner 447 448 Collective on PetscPartitioner 449 450 Input Parameter: 451 + part - the PetscPartitioner object to view 452 - v - the viewer 453 454 Level: developer 455 456 .seealso: PetscPartitionerDestroy() 457 @*/ 458 PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v) 459 { 460 PetscErrorCode ierr; 461 462 PetscFunctionBegin; 463 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 464 if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);} 465 if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);} 466 PetscFunctionReturn(0); 467 } 468 469 PetscErrorCode PetscPartitionerSetTypeFromOptions_Internal(PetscPartitioner part) 470 { 471 const char *defaultType; 472 char name[256]; 473 PetscBool flg; 474 PetscErrorCode ierr; 475 476 PetscFunctionBegin; 477 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 478 if (!((PetscObject) part)->type_name) 479 #if defined(PETSC_HAVE_CHACO) 480 defaultType = PETSCPARTITIONERCHACO; 481 #elif defined(PETSC_HAVE_PARMETIS) 482 defaultType = PETSCPARTITIONERPARMETIS; 483 #else 484 defaultType = PETSCPARTITIONERSIMPLE; 485 #endif 486 else 487 defaultType = ((PetscObject) part)->type_name; 488 ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr); 489 490 ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr); 491 ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, 256, &flg);CHKERRQ(ierr); 492 if (flg) { 493 ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr); 494 } else if (!((PetscObject) part)->type_name) { 495 ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr); 496 } 497 ierr = PetscOptionsEnd();CHKERRQ(ierr); 498 PetscFunctionReturn(0); 499 } 500 501 /*@ 502 PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database 503 504 Collective on PetscPartitioner 505 506 Input Parameter: 507 . part - the PetscPartitioner object to set options for 508 509 Level: developer 510 511 .seealso: PetscPartitionerView() 512 @*/ 513 PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part) 514 { 515 PetscErrorCode ierr; 516 517 PetscFunctionBegin; 518 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 519 ierr = PetscPartitionerSetTypeFromOptions_Internal(part);CHKERRQ(ierr); 520 521 ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr); 522 if (part->ops->setfromoptions) {ierr = (*part->ops->setfromoptions)(PetscOptionsObject,part);CHKERRQ(ierr);} 523 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 524 ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) part);CHKERRQ(ierr); 525 ierr = PetscOptionsEnd();CHKERRQ(ierr); 526 ierr = PetscPartitionerViewFromOptions(part, NULL, "-petscpartitioner_view");CHKERRQ(ierr); 527 PetscFunctionReturn(0); 528 } 529 530 /*@C 531 PetscPartitionerSetUp - Construct data structures for the PetscPartitioner 532 533 Collective on PetscPartitioner 534 535 Input Parameter: 536 . part - the PetscPartitioner object to setup 537 538 Level: developer 539 540 .seealso: PetscPartitionerView(), PetscPartitionerDestroy() 541 @*/ 542 PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part) 543 { 544 PetscErrorCode ierr; 545 546 PetscFunctionBegin; 547 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 548 if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);} 549 PetscFunctionReturn(0); 550 } 551 552 /*@ 553 PetscPartitionerDestroy - Destroys a PetscPartitioner object 554 555 Collective on PetscPartitioner 556 557 Input Parameter: 558 . part - the PetscPartitioner object to destroy 559 560 Level: developer 561 562 .seealso: PetscPartitionerView() 563 @*/ 564 PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part) 565 { 566 PetscErrorCode ierr; 567 568 PetscFunctionBegin; 569 if (!*part) PetscFunctionReturn(0); 570 PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1); 571 572 if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);} 573 ((PetscObject) (*part))->refct = 0; 574 575 if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);} 576 ierr = PetscHeaderDestroy(part);CHKERRQ(ierr); 577 PetscFunctionReturn(0); 578 } 579 580 /*@ 581 PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType(). 582 583 Collective on MPI_Comm 584 585 Input Parameter: 586 . comm - The communicator for the PetscPartitioner object 587 588 Output Parameter: 589 . part - The PetscPartitioner object 590 591 Level: beginner 592 593 .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL, PETSCPARTITIONERSIMPLE, PETSCPARTITIONERGATHER 594 @*/ 595 PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part) 596 { 597 PetscPartitioner p; 598 PetscErrorCode ierr; 599 600 PetscFunctionBegin; 601 PetscValidPointer(part, 2); 602 *part = NULL; 603 ierr = DMInitializePackage();CHKERRQ(ierr); 604 605 ierr = PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr); 606 607 *part = p; 608 PetscFunctionReturn(0); 609 } 610 611 /*@ 612 PetscPartitionerPartition - Create a non-overlapping partition of the cells in the mesh 613 614 Collective on DM 615 616 Input Parameters: 617 + part - The PetscPartitioner 618 - dm - The mesh DM 619 620 Output Parameters: 621 + partSection - The PetscSection giving the division of points by partition 622 - partition - The list of points by partition 623 624 Note: Instead of cells, points at a given height can be partitioned by calling PetscPartitionerSetPointHeight() 625 626 Level: developer 627 628 .seealso DMPlexDistribute(), PetscPartitionerSetPointHeight(), PetscPartitionerCreate() 629 @*/ 630 PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, DM dm, PetscSection partSection, IS *partition) 631 { 632 PetscMPIInt size; 633 PetscErrorCode ierr; 634 635 PetscFunctionBegin; 636 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 637 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 638 PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4); 639 PetscValidPointer(partition, 5); 640 ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr); 641 if (size == 1) { 642 PetscInt *points; 643 PetscInt cStart, cEnd, c; 644 645 ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr); 646 ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr); 647 ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr); 648 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 649 ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr); 650 for (c = cStart; c < cEnd; ++c) points[c] = c; 651 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 652 PetscFunctionReturn(0); 653 } 654 /* Obvious cheating, but I cannot think of a better way to do this. The DMSetFromOptions() has refinement in it, 655 so we cannot call it and have it feed down to the partitioner before partitioning */ 656 ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr); 657 if (part->height == 0) { 658 PetscInt numVertices; 659 PetscInt *start = NULL; 660 PetscInt *adjacency = NULL; 661 IS globalNumbering; 662 663 ierr = DMPlexCreatePartitionerGraph(dm, 0, &numVertices, &start, &adjacency, &globalNumbering);CHKERRQ(ierr); 664 if (!part->ops->partition) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONGSTATE, "PetscPartitioner has no type"); 665 ierr = (*part->ops->partition)(part, dm, size, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr); 666 ierr = PetscFree(start);CHKERRQ(ierr); 667 ierr = PetscFree(adjacency);CHKERRQ(ierr); 668 if (globalNumbering) { /* partition is wrt global unique numbering: change this to be wrt local numbering */ 669 const PetscInt *globalNum; 670 const PetscInt *partIdx; 671 PetscInt *map, cStart, cEnd; 672 PetscInt *adjusted, i, localSize, offset; 673 IS newPartition; 674 675 ierr = ISGetLocalSize(*partition,&localSize);CHKERRQ(ierr); 676 ierr = PetscMalloc1(localSize,&adjusted);CHKERRQ(ierr); 677 ierr = ISGetIndices(globalNumbering,&globalNum);CHKERRQ(ierr); 678 ierr = ISGetIndices(*partition,&partIdx);CHKERRQ(ierr); 679 ierr = PetscMalloc1(localSize,&map);CHKERRQ(ierr); 680 ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr); 681 for (i = cStart, offset = 0; i < cEnd; i++) { 682 if (globalNum[i - cStart] >= 0) map[offset++] = i; 683 } 684 for (i = 0; i < localSize; i++) { 685 adjusted[i] = map[partIdx[i]]; 686 } 687 ierr = PetscFree(map);CHKERRQ(ierr); 688 ierr = ISRestoreIndices(*partition,&partIdx);CHKERRQ(ierr); 689 ierr = ISRestoreIndices(globalNumbering,&globalNum);CHKERRQ(ierr); 690 ierr = ISCreateGeneral(PETSC_COMM_SELF,localSize,adjusted,PETSC_OWN_POINTER,&newPartition);CHKERRQ(ierr); 691 ierr = ISDestroy(&globalNumbering);CHKERRQ(ierr); 692 ierr = ISDestroy(partition);CHKERRQ(ierr); 693 *partition = newPartition; 694 } 695 } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height); 696 PetscFunctionReturn(0); 697 698 } 699 700 static PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part) 701 { 702 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 703 PetscErrorCode ierr; 704 705 PetscFunctionBegin; 706 ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr); 707 ierr = ISDestroy(&p->partition);CHKERRQ(ierr); 708 ierr = PetscFree(p);CHKERRQ(ierr); 709 PetscFunctionReturn(0); 710 } 711 712 static PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer) 713 { 714 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 715 PetscViewerFormat format; 716 PetscErrorCode ierr; 717 718 PetscFunctionBegin; 719 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 720 ierr = PetscViewerASCIIPrintf(viewer, "Shell Graph Partitioner:\n");CHKERRQ(ierr); 721 if (p->random) { 722 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 723 ierr = PetscViewerASCIIPrintf(viewer, "using random partition\n");CHKERRQ(ierr); 724 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 725 } 726 PetscFunctionReturn(0); 727 } 728 729 static PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer) 730 { 731 PetscBool iascii; 732 PetscErrorCode ierr; 733 734 PetscFunctionBegin; 735 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 736 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 737 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 738 if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);} 739 PetscFunctionReturn(0); 740 } 741 742 static PetscErrorCode PetscPartitionerSetFromOptions_Shell(PetscOptionItems *PetscOptionsObject, PetscPartitioner part) 743 { 744 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 745 PetscErrorCode ierr; 746 747 PetscFunctionBegin; 748 ierr = PetscOptionsHead(PetscOptionsObject, "PetscPartitionerShell Options");CHKERRQ(ierr); 749 ierr = PetscOptionsBool("-petscpartitioner_shell_random", "Use a random partition", "PetscPartitionerView", PETSC_FALSE, &p->random, NULL);CHKERRQ(ierr); 750 ierr = PetscOptionsTail();CHKERRQ(ierr); 751 PetscFunctionReturn(0); 752 } 753 754 static PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) 755 { 756 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 757 PetscInt np; 758 PetscErrorCode ierr; 759 760 PetscFunctionBegin; 761 if (p->random) { 762 PetscRandom r; 763 PetscInt *sizes, *points, v, p; 764 PetscMPIInt rank; 765 766 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr); 767 ierr = PetscRandomCreate(PETSC_COMM_SELF, &r);CHKERRQ(ierr); 768 ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) nparts);CHKERRQ(ierr); 769 ierr = PetscRandomSetFromOptions(r);CHKERRQ(ierr); 770 ierr = PetscCalloc2(nparts, &sizes, numVertices, &points);CHKERRQ(ierr); 771 for (v = 0; v < numVertices; ++v) {points[v] = v;} 772 for (p = 0; p < nparts; ++p) {sizes[p] = numVertices/nparts + (PetscInt) (p < numVertices % nparts);} 773 for (v = numVertices-1; v > 0; --v) { 774 PetscReal val; 775 PetscInt w, tmp; 776 777 ierr = PetscRandomSetInterval(r, 0.0, (PetscScalar) (v+1));CHKERRQ(ierr); 778 ierr = PetscRandomGetValueReal(r, &val);CHKERRQ(ierr); 779 w = PetscFloorReal(val); 780 tmp = points[v]; 781 points[v] = points[w]; 782 points[w] = tmp; 783 } 784 ierr = PetscRandomDestroy(&r);CHKERRQ(ierr); 785 ierr = PetscPartitionerShellSetPartition(part, nparts, sizes, points);CHKERRQ(ierr); 786 ierr = PetscFree2(sizes, points);CHKERRQ(ierr); 787 } 788 if (!p->section) SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Shell partitioner information not provided. Please call PetscPartitionerShellSetPartition()"); 789 ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr); 790 if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np); 791 ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr); 792 if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np); 793 ierr = PetscSectionCopy(p->section, partSection);CHKERRQ(ierr); 794 *partition = p->partition; 795 ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr); 796 PetscFunctionReturn(0); 797 } 798 799 static PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part) 800 { 801 PetscFunctionBegin; 802 part->ops->view = PetscPartitionerView_Shell; 803 part->ops->setfromoptions = PetscPartitionerSetFromOptions_Shell; 804 part->ops->destroy = PetscPartitionerDestroy_Shell; 805 part->ops->partition = PetscPartitionerPartition_Shell; 806 PetscFunctionReturn(0); 807 } 808 809 /*MC 810 PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object 811 812 Level: intermediate 813 814 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() 815 M*/ 816 817 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part) 818 { 819 PetscPartitioner_Shell *p; 820 PetscErrorCode ierr; 821 822 PetscFunctionBegin; 823 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 824 ierr = PetscNewLog(part, &p);CHKERRQ(ierr); 825 part->data = p; 826 827 ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr); 828 p->random = PETSC_FALSE; 829 PetscFunctionReturn(0); 830 } 831 832 /*@C 833 PetscPartitionerShellSetPartition - Set an artifical partition for a mesh 834 835 Collective on Part 836 837 Input Parameters: 838 + part - The PetscPartitioner 839 . size - The number of partitions 840 . sizes - array of size size (or NULL) providing the number of points in each partition 841 - 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.) 842 843 Level: developer 844 845 Notes: 846 847 It is safe to free the sizes and points arrays after use in this routine. 848 849 .seealso DMPlexDistribute(), PetscPartitionerCreate() 850 @*/ 851 PetscErrorCode PetscPartitionerShellSetPartition(PetscPartitioner part, PetscInt size, const PetscInt sizes[], const PetscInt points[]) 852 { 853 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 854 PetscInt proc, numPoints; 855 PetscErrorCode ierr; 856 857 PetscFunctionBegin; 858 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 859 if (sizes) {PetscValidPointer(sizes, 3);} 860 if (points) {PetscValidPointer(points, 4);} 861 ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr); 862 ierr = ISDestroy(&p->partition);CHKERRQ(ierr); 863 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) part), &p->section);CHKERRQ(ierr); 864 ierr = PetscSectionSetChart(p->section, 0, size);CHKERRQ(ierr); 865 if (sizes) { 866 for (proc = 0; proc < size; ++proc) { 867 ierr = PetscSectionSetDof(p->section, proc, sizes[proc]);CHKERRQ(ierr); 868 } 869 } 870 ierr = PetscSectionSetUp(p->section);CHKERRQ(ierr); 871 ierr = PetscSectionGetStorageSize(p->section, &numPoints);CHKERRQ(ierr); 872 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), numPoints, points, PETSC_COPY_VALUES, &p->partition);CHKERRQ(ierr); 873 PetscFunctionReturn(0); 874 } 875 876 /*@ 877 PetscPartitionerShellSetRandom - Set the flag to use a random partition 878 879 Collective on Part 880 881 Input Parameters: 882 + part - The PetscPartitioner 883 - random - The flag to use a random partition 884 885 Level: intermediate 886 887 .seealso PetscPartitionerShellGetRandom(), PetscPartitionerCreate() 888 @*/ 889 PetscErrorCode PetscPartitionerShellSetRandom(PetscPartitioner part, PetscBool random) 890 { 891 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 892 893 PetscFunctionBegin; 894 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 895 p->random = random; 896 PetscFunctionReturn(0); 897 } 898 899 /*@ 900 PetscPartitionerShellGetRandom - get the flag to use a random partition 901 902 Collective on Part 903 904 Input Parameter: 905 . part - The PetscPartitioner 906 907 Output Parameter 908 . random - The flag to use a random partition 909 910 Level: intermediate 911 912 .seealso PetscPartitionerShellSetRandom(), PetscPartitionerCreate() 913 @*/ 914 PetscErrorCode PetscPartitionerShellGetRandom(PetscPartitioner part, PetscBool *random) 915 { 916 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 917 918 PetscFunctionBegin; 919 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 920 PetscValidPointer(random, 2); 921 *random = p->random; 922 PetscFunctionReturn(0); 923 } 924 925 static PetscErrorCode PetscPartitionerDestroy_Simple(PetscPartitioner part) 926 { 927 PetscPartitioner_Simple *p = (PetscPartitioner_Simple *) part->data; 928 PetscErrorCode ierr; 929 930 PetscFunctionBegin; 931 ierr = PetscFree(p);CHKERRQ(ierr); 932 PetscFunctionReturn(0); 933 } 934 935 static PetscErrorCode PetscPartitionerView_Simple_Ascii(PetscPartitioner part, PetscViewer viewer) 936 { 937 PetscViewerFormat format; 938 PetscErrorCode ierr; 939 940 PetscFunctionBegin; 941 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 942 ierr = PetscViewerASCIIPrintf(viewer, "Simple Graph Partitioner:\n");CHKERRQ(ierr); 943 PetscFunctionReturn(0); 944 } 945 946 static PetscErrorCode PetscPartitionerView_Simple(PetscPartitioner part, PetscViewer viewer) 947 { 948 PetscBool iascii; 949 PetscErrorCode ierr; 950 951 PetscFunctionBegin; 952 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 953 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 954 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 955 if (iascii) {ierr = PetscPartitionerView_Simple_Ascii(part, viewer);CHKERRQ(ierr);} 956 PetscFunctionReturn(0); 957 } 958 959 static PetscErrorCode PetscPartitionerPartition_Simple(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) 960 { 961 MPI_Comm comm; 962 PetscInt np; 963 PetscMPIInt size; 964 PetscErrorCode ierr; 965 966 PetscFunctionBegin; 967 comm = PetscObjectComm((PetscObject)dm); 968 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 969 ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); 970 ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr); 971 if (size == 1) { 972 for (np = 0; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, numVertices/nparts + ((numVertices % nparts) > np));CHKERRQ(ierr);} 973 } 974 else { 975 PetscMPIInt rank; 976 PetscInt nvGlobal, *offsets, myFirst, myLast; 977 978 ierr = PetscMalloc1(size+1,&offsets);CHKERRQ(ierr); 979 offsets[0] = 0; 980 ierr = MPI_Allgather(&numVertices,1,MPIU_INT,&offsets[1],1,MPIU_INT,comm);CHKERRQ(ierr); 981 for (np = 2; np <= size; np++) { 982 offsets[np] += offsets[np-1]; 983 } 984 nvGlobal = offsets[size]; 985 ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr); 986 myFirst = offsets[rank]; 987 myLast = offsets[rank + 1] - 1; 988 ierr = PetscFree(offsets);CHKERRQ(ierr); 989 if (numVertices) { 990 PetscInt firstPart = 0, firstLargePart = 0; 991 PetscInt lastPart = 0, lastLargePart = 0; 992 PetscInt rem = nvGlobal % nparts; 993 PetscInt pSmall = nvGlobal/nparts; 994 PetscInt pBig = nvGlobal/nparts + 1; 995 996 997 if (rem) { 998 firstLargePart = myFirst / pBig; 999 lastLargePart = myLast / pBig; 1000 1001 if (firstLargePart < rem) { 1002 firstPart = firstLargePart; 1003 } 1004 else { 1005 firstPart = rem + (myFirst - (rem * pBig)) / pSmall; 1006 } 1007 if (lastLargePart < rem) { 1008 lastPart = lastLargePart; 1009 } 1010 else { 1011 lastPart = rem + (myLast - (rem * pBig)) / pSmall; 1012 } 1013 } 1014 else { 1015 firstPart = myFirst / (nvGlobal/nparts); 1016 lastPart = myLast / (nvGlobal/nparts); 1017 } 1018 1019 for (np = firstPart; np <= lastPart; np++) { 1020 PetscInt PartStart = np * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np); 1021 PetscInt PartEnd = (np+1) * (nvGlobal/nparts) + PetscMin(nvGlobal % nparts,np+1); 1022 1023 PartStart = PetscMax(PartStart,myFirst); 1024 PartEnd = PetscMin(PartEnd,myLast+1); 1025 ierr = PetscSectionSetDof(partSection,np,PartEnd-PartStart);CHKERRQ(ierr); 1026 } 1027 } 1028 } 1029 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 1030 PetscFunctionReturn(0); 1031 } 1032 1033 static PetscErrorCode PetscPartitionerInitialize_Simple(PetscPartitioner part) 1034 { 1035 PetscFunctionBegin; 1036 part->ops->view = PetscPartitionerView_Simple; 1037 part->ops->destroy = PetscPartitionerDestroy_Simple; 1038 part->ops->partition = PetscPartitionerPartition_Simple; 1039 PetscFunctionReturn(0); 1040 } 1041 1042 /*MC 1043 PETSCPARTITIONERSIMPLE = "simple" - A PetscPartitioner object 1044 1045 Level: intermediate 1046 1047 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() 1048 M*/ 1049 1050 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Simple(PetscPartitioner part) 1051 { 1052 PetscPartitioner_Simple *p; 1053 PetscErrorCode ierr; 1054 1055 PetscFunctionBegin; 1056 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 1057 ierr = PetscNewLog(part, &p);CHKERRQ(ierr); 1058 part->data = p; 1059 1060 ierr = PetscPartitionerInitialize_Simple(part);CHKERRQ(ierr); 1061 PetscFunctionReturn(0); 1062 } 1063 1064 static PetscErrorCode PetscPartitionerDestroy_Gather(PetscPartitioner part) 1065 { 1066 PetscPartitioner_Gather *p = (PetscPartitioner_Gather *) part->data; 1067 PetscErrorCode ierr; 1068 1069 PetscFunctionBegin; 1070 ierr = PetscFree(p);CHKERRQ(ierr); 1071 PetscFunctionReturn(0); 1072 } 1073 1074 static PetscErrorCode PetscPartitionerView_Gather_Ascii(PetscPartitioner part, PetscViewer viewer) 1075 { 1076 PetscViewerFormat format; 1077 PetscErrorCode ierr; 1078 1079 PetscFunctionBegin; 1080 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1081 ierr = PetscViewerASCIIPrintf(viewer, "Gather Graph Partitioner:\n");CHKERRQ(ierr); 1082 PetscFunctionReturn(0); 1083 } 1084 1085 static PetscErrorCode PetscPartitionerView_Gather(PetscPartitioner part, PetscViewer viewer) 1086 { 1087 PetscBool iascii; 1088 PetscErrorCode ierr; 1089 1090 PetscFunctionBegin; 1091 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 1092 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1093 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 1094 if (iascii) {ierr = PetscPartitionerView_Gather_Ascii(part, viewer);CHKERRQ(ierr);} 1095 PetscFunctionReturn(0); 1096 } 1097 1098 static PetscErrorCode PetscPartitionerPartition_Gather(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) 1099 { 1100 PetscInt np; 1101 PetscErrorCode ierr; 1102 1103 PetscFunctionBegin; 1104 ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); 1105 ierr = ISCreateStride(PETSC_COMM_SELF, numVertices, 0, 1, partition);CHKERRQ(ierr); 1106 ierr = PetscSectionSetDof(partSection,0,numVertices);CHKERRQ(ierr); 1107 for (np = 1; np < nparts; ++np) {ierr = PetscSectionSetDof(partSection, np, 0);CHKERRQ(ierr);} 1108 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 1109 PetscFunctionReturn(0); 1110 } 1111 1112 static PetscErrorCode PetscPartitionerInitialize_Gather(PetscPartitioner part) 1113 { 1114 PetscFunctionBegin; 1115 part->ops->view = PetscPartitionerView_Gather; 1116 part->ops->destroy = PetscPartitionerDestroy_Gather; 1117 part->ops->partition = PetscPartitionerPartition_Gather; 1118 PetscFunctionReturn(0); 1119 } 1120 1121 /*MC 1122 PETSCPARTITIONERGATHER = "gather" - A PetscPartitioner object 1123 1124 Level: intermediate 1125 1126 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() 1127 M*/ 1128 1129 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Gather(PetscPartitioner part) 1130 { 1131 PetscPartitioner_Gather *p; 1132 PetscErrorCode ierr; 1133 1134 PetscFunctionBegin; 1135 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 1136 ierr = PetscNewLog(part, &p);CHKERRQ(ierr); 1137 part->data = p; 1138 1139 ierr = PetscPartitionerInitialize_Gather(part);CHKERRQ(ierr); 1140 PetscFunctionReturn(0); 1141 } 1142 1143 1144 static PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part) 1145 { 1146 PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data; 1147 PetscErrorCode ierr; 1148 1149 PetscFunctionBegin; 1150 ierr = PetscFree(p);CHKERRQ(ierr); 1151 PetscFunctionReturn(0); 1152 } 1153 1154 static PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer) 1155 { 1156 PetscViewerFormat format; 1157 PetscErrorCode ierr; 1158 1159 PetscFunctionBegin; 1160 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1161 ierr = PetscViewerASCIIPrintf(viewer, "Chaco Graph Partitioner:\n");CHKERRQ(ierr); 1162 PetscFunctionReturn(0); 1163 } 1164 1165 static PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer) 1166 { 1167 PetscBool iascii; 1168 PetscErrorCode ierr; 1169 1170 PetscFunctionBegin; 1171 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 1172 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1173 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 1174 if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);} 1175 PetscFunctionReturn(0); 1176 } 1177 1178 #if defined(PETSC_HAVE_CHACO) 1179 #if defined(PETSC_HAVE_UNISTD_H) 1180 #include <unistd.h> 1181 #endif 1182 #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT) 1183 #include <chaco.h> 1184 #else 1185 /* Older versions of Chaco do not have an include file */ 1186 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts, 1187 float *ewgts, float *x, float *y, float *z, char *outassignname, 1188 char *outfilename, short *assignment, int architecture, int ndims_tot, 1189 int mesh_dims[3], double *goal, int global_method, int local_method, 1190 int rqi_flag, int vmax, int ndims, double eigtol, long seed); 1191 #endif 1192 extern int FREE_GRAPH; 1193 #endif 1194 1195 static PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) 1196 { 1197 #if defined(PETSC_HAVE_CHACO) 1198 enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3}; 1199 MPI_Comm comm; 1200 int nvtxs = numVertices; /* number of vertices in full graph */ 1201 int *vwgts = NULL; /* weights for all vertices */ 1202 float *ewgts = NULL; /* weights for all edges */ 1203 float *x = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */ 1204 char *outassignname = NULL; /* name of assignment output file */ 1205 char *outfilename = NULL; /* output file name */ 1206 int architecture = 1; /* 0 => hypercube, d => d-dimensional mesh */ 1207 int ndims_tot = 0; /* total number of cube dimensions to divide */ 1208 int mesh_dims[3]; /* dimensions of mesh of processors */ 1209 double *goal = NULL; /* desired set sizes for each set */ 1210 int global_method = 1; /* global partitioning algorithm */ 1211 int local_method = 1; /* local partitioning algorithm */ 1212 int rqi_flag = 0; /* should I use RQI/Symmlq eigensolver? */ 1213 int vmax = 200; /* how many vertices to coarsen down to? */ 1214 int ndims = 1; /* number of eigenvectors (2^d sets) */ 1215 double eigtol = 0.001; /* tolerance on eigenvectors */ 1216 long seed = 123636512; /* for random graph mutations */ 1217 #if defined(PETSC_HAVE_CHACO_INT_ASSIGNMENT) 1218 int *assignment; /* Output partition */ 1219 #else 1220 short int *assignment; /* Output partition */ 1221 #endif 1222 int fd_stdout, fd_pipe[2]; 1223 PetscInt *points; 1224 int i, v, p; 1225 PetscErrorCode ierr; 1226 1227 PetscFunctionBegin; 1228 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 1229 if (!numVertices) { 1230 ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); 1231 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 1232 ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 1233 PetscFunctionReturn(0); 1234 } 1235 FREE_GRAPH = 0; /* Do not let Chaco free my memory */ 1236 for (i = 0; i < start[numVertices]; ++i) ++adjacency[i]; 1237 1238 if (global_method == INERTIAL_METHOD) { 1239 /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */ 1240 SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported"); 1241 } 1242 mesh_dims[0] = nparts; 1243 mesh_dims[1] = 1; 1244 mesh_dims[2] = 1; 1245 ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr); 1246 /* Chaco outputs to stdout. We redirect this to a buffer. */ 1247 /* TODO: check error codes for UNIX calls */ 1248 #if defined(PETSC_HAVE_UNISTD_H) 1249 { 1250 int piperet; 1251 piperet = pipe(fd_pipe); 1252 if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe"); 1253 fd_stdout = dup(1); 1254 close(1); 1255 dup2(fd_pipe[1], 1); 1256 } 1257 #endif 1258 ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename, 1259 assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag, 1260 vmax, ndims, eigtol, seed); 1261 #if defined(PETSC_HAVE_UNISTD_H) 1262 { 1263 char msgLog[10000]; 1264 int count; 1265 1266 fflush(stdout); 1267 count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char)); 1268 if (count < 0) count = 0; 1269 msgLog[count] = 0; 1270 close(1); 1271 dup2(fd_stdout, 1); 1272 close(fd_stdout); 1273 close(fd_pipe[0]); 1274 close(fd_pipe[1]); 1275 if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog); 1276 } 1277 #endif 1278 /* Convert to PetscSection+IS */ 1279 ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); 1280 for (v = 0; v < nvtxs; ++v) { 1281 ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr); 1282 } 1283 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 1284 ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr); 1285 for (p = 0, i = 0; p < nparts; ++p) { 1286 for (v = 0; v < nvtxs; ++v) { 1287 if (assignment[v] == p) points[i++] = v; 1288 } 1289 } 1290 if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs); 1291 ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 1292 if (global_method == INERTIAL_METHOD) { 1293 /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */ 1294 } 1295 ierr = PetscFree(assignment);CHKERRQ(ierr); 1296 for (i = 0; i < start[numVertices]; ++i) --adjacency[i]; 1297 PetscFunctionReturn(0); 1298 #else 1299 SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco."); 1300 #endif 1301 } 1302 1303 static PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part) 1304 { 1305 PetscFunctionBegin; 1306 part->ops->view = PetscPartitionerView_Chaco; 1307 part->ops->destroy = PetscPartitionerDestroy_Chaco; 1308 part->ops->partition = PetscPartitionerPartition_Chaco; 1309 PetscFunctionReturn(0); 1310 } 1311 1312 /*MC 1313 PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library 1314 1315 Level: intermediate 1316 1317 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() 1318 M*/ 1319 1320 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part) 1321 { 1322 PetscPartitioner_Chaco *p; 1323 PetscErrorCode ierr; 1324 1325 PetscFunctionBegin; 1326 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 1327 ierr = PetscNewLog(part, &p);CHKERRQ(ierr); 1328 part->data = p; 1329 1330 ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr); 1331 ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr); 1332 PetscFunctionReturn(0); 1333 } 1334 1335 static PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part) 1336 { 1337 PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data; 1338 PetscErrorCode ierr; 1339 1340 PetscFunctionBegin; 1341 ierr = PetscFree(p);CHKERRQ(ierr); 1342 PetscFunctionReturn(0); 1343 } 1344 1345 static PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer) 1346 { 1347 PetscViewerFormat format; 1348 PetscErrorCode ierr; 1349 1350 PetscFunctionBegin; 1351 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1352 ierr = PetscViewerASCIIPrintf(viewer, "ParMetis Graph Partitioner:\n");CHKERRQ(ierr); 1353 PetscFunctionReturn(0); 1354 } 1355 1356 static PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer) 1357 { 1358 PetscBool iascii; 1359 PetscErrorCode ierr; 1360 1361 PetscFunctionBegin; 1362 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 1363 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1364 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 1365 if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);} 1366 PetscFunctionReturn(0); 1367 } 1368 1369 #if defined(PETSC_HAVE_PARMETIS) 1370 #include <parmetis.h> 1371 #endif 1372 1373 static PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) 1374 { 1375 #if defined(PETSC_HAVE_PARMETIS) 1376 MPI_Comm comm; 1377 PetscSection section; 1378 PetscInt nvtxs = numVertices; /* The number of vertices in full graph */ 1379 PetscInt *vtxdist; /* Distribution of vertices across processes */ 1380 PetscInt *xadj = start; /* Start of edge list for each vertex */ 1381 PetscInt *adjncy = adjacency; /* Edge lists for all vertices */ 1382 PetscInt *vwgt = NULL; /* Vertex weights */ 1383 PetscInt *adjwgt = NULL; /* Edge weights */ 1384 PetscInt wgtflag = 0; /* Indicates which weights are present */ 1385 PetscInt numflag = 0; /* Indicates initial offset (0 or 1) */ 1386 PetscInt ncon = 1; /* The number of weights per vertex */ 1387 PetscReal *tpwgts; /* The fraction of vertex weights assigned to each partition */ 1388 PetscReal *ubvec; /* The balance intolerance for vertex weights */ 1389 PetscInt options[5]; /* Options */ 1390 /* Outputs */ 1391 PetscInt edgeCut; /* The number of edges cut by the partition */ 1392 PetscInt *assignment, *points; 1393 PetscMPIInt rank, p, v, i; 1394 PetscErrorCode ierr; 1395 1396 PetscFunctionBegin; 1397 ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr); 1398 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 1399 options[0] = 0; /* Use all defaults */ 1400 /* Calculate vertex distribution */ 1401 ierr = PetscMalloc5(nparts+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment,nvtxs,&vwgt);CHKERRQ(ierr); 1402 vtxdist[0] = 0; 1403 ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr); 1404 for (p = 2; p <= nparts; ++p) { 1405 vtxdist[p] += vtxdist[p-1]; 1406 } 1407 /* Calculate weights */ 1408 for (p = 0; p < nparts; ++p) { 1409 tpwgts[p] = 1.0/nparts; 1410 } 1411 ubvec[0] = 1.05; 1412 /* Weight cells by dofs on cell by default */ 1413 ierr = DMGetDefaultSection(dm, §ion);CHKERRQ(ierr); 1414 if (section) { 1415 PetscInt cStart, cEnd, dof; 1416 1417 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 1418 for (v = cStart; v < cEnd; ++v) { 1419 ierr = PetscSectionGetDof(section, v, &dof);CHKERRQ(ierr); 1420 vwgt[v-cStart] = PetscMax(dof, 1); 1421 } 1422 } else { 1423 for (v = 0; v < nvtxs; ++v) vwgt[v] = 1; 1424 } 1425 1426 if (nparts == 1) { 1427 ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));CHKERRQ(ierr); 1428 } else { 1429 if (vtxdist[1] == vtxdist[nparts]) { 1430 if (!rank) { 1431 PetscStackPush("METIS_PartGraphKway"); 1432 ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment); 1433 PetscStackPop; 1434 if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()"); 1435 } 1436 } else { 1437 PetscStackPush("ParMETIS_V3_PartKway"); 1438 ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm); 1439 PetscStackPop; 1440 if (ierr != METIS_OK) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error %d in ParMETIS_V3_PartKway()", ierr); 1441 } 1442 } 1443 /* Convert to PetscSection+IS */ 1444 ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); 1445 for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);} 1446 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 1447 ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr); 1448 for (p = 0, i = 0; p < nparts; ++p) { 1449 for (v = 0; v < nvtxs; ++v) { 1450 if (assignment[v] == p) points[i++] = v; 1451 } 1452 } 1453 if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs); 1454 ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 1455 ierr = PetscFree5(vtxdist,tpwgts,ubvec,assignment,vwgt);CHKERRQ(ierr); 1456 PetscFunctionReturn(0); 1457 #else 1458 SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis."); 1459 #endif 1460 } 1461 1462 static PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part) 1463 { 1464 PetscFunctionBegin; 1465 part->ops->view = PetscPartitionerView_ParMetis; 1466 part->ops->destroy = PetscPartitionerDestroy_ParMetis; 1467 part->ops->partition = PetscPartitionerPartition_ParMetis; 1468 PetscFunctionReturn(0); 1469 } 1470 1471 /*MC 1472 PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMetis library 1473 1474 Level: intermediate 1475 1476 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() 1477 M*/ 1478 1479 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part) 1480 { 1481 PetscPartitioner_ParMetis *p; 1482 PetscErrorCode ierr; 1483 1484 PetscFunctionBegin; 1485 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 1486 ierr = PetscNewLog(part, &p);CHKERRQ(ierr); 1487 part->data = p; 1488 1489 ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr); 1490 ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr); 1491 PetscFunctionReturn(0); 1492 } 1493 1494 /*@ 1495 DMPlexGetPartitioner - Get the mesh partitioner 1496 1497 Not collective 1498 1499 Input Parameter: 1500 . dm - The DM 1501 1502 Output Parameter: 1503 . part - The PetscPartitioner 1504 1505 Level: developer 1506 1507 Note: This gets a borrowed reference, so the user should not destroy this PetscPartitioner. 1508 1509 .seealso DMPlexDistribute(), DMPlexSetPartitioner(), PetscPartitionerCreate() 1510 @*/ 1511 PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part) 1512 { 1513 DM_Plex *mesh = (DM_Plex *) dm->data; 1514 PetscErrorCode ierr; 1515 1516 PetscFunctionBegin; 1517 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1518 PetscValidPointer(part, 2); 1519 ierr = PetscPartitionerSetTypeFromOptions_Internal(mesh->partitioner);CHKERRQ(ierr); 1520 *part = mesh->partitioner; 1521 PetscFunctionReturn(0); 1522 } 1523 1524 /*@ 1525 DMPlexSetPartitioner - Set the mesh partitioner 1526 1527 logically collective on dm and part 1528 1529 Input Parameters: 1530 + dm - The DM 1531 - part - The partitioner 1532 1533 Level: developer 1534 1535 Note: Any existing PetscPartitioner will be destroyed. 1536 1537 .seealso DMPlexDistribute(), DMPlexGetPartitioner(), PetscPartitionerCreate() 1538 @*/ 1539 PetscErrorCode DMPlexSetPartitioner(DM dm, PetscPartitioner part) 1540 { 1541 DM_Plex *mesh = (DM_Plex *) dm->data; 1542 PetscErrorCode ierr; 1543 1544 PetscFunctionBegin; 1545 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1546 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 2); 1547 ierr = PetscObjectReference((PetscObject)part);CHKERRQ(ierr); 1548 ierr = PetscPartitionerDestroy(&mesh->partitioner);CHKERRQ(ierr); 1549 mesh->partitioner = part; 1550 PetscFunctionReturn(0); 1551 } 1552 1553 static PetscErrorCode DMPlexPartitionLabelClosure_Tree(DM dm, DMLabel label, PetscInt rank, PetscInt point, PetscBool up, PetscBool down) 1554 { 1555 PetscErrorCode ierr; 1556 1557 PetscFunctionBegin; 1558 if (up) { 1559 PetscInt parent; 1560 1561 ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr); 1562 if (parent != point) { 1563 PetscInt closureSize, *closure = NULL, i; 1564 1565 ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 1566 for (i = 0; i < closureSize; i++) { 1567 PetscInt cpoint = closure[2*i]; 1568 1569 ierr = DMLabelSetValue(label,cpoint,rank);CHKERRQ(ierr); 1570 ierr = DMPlexPartitionLabelClosure_Tree(dm,label,rank,cpoint,PETSC_TRUE,PETSC_FALSE);CHKERRQ(ierr); 1571 } 1572 ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 1573 } 1574 } 1575 if (down) { 1576 PetscInt numChildren; 1577 const PetscInt *children; 1578 1579 ierr = DMPlexGetTreeChildren(dm,point,&numChildren,&children);CHKERRQ(ierr); 1580 if (numChildren) { 1581 PetscInt i; 1582 1583 for (i = 0; i < numChildren; i++) { 1584 PetscInt cpoint = children[i]; 1585 1586 ierr = DMLabelSetValue(label,cpoint,rank);CHKERRQ(ierr); 1587 ierr = DMPlexPartitionLabelClosure_Tree(dm,label,rank,cpoint,PETSC_FALSE,PETSC_TRUE);CHKERRQ(ierr); 1588 } 1589 } 1590 } 1591 PetscFunctionReturn(0); 1592 } 1593 1594 /*@ 1595 DMPlexPartitionLabelClosure - Add the closure of all points to the partition label 1596 1597 Input Parameters: 1598 + dm - The DM 1599 - label - DMLabel assinging ranks to remote roots 1600 1601 Level: developer 1602 1603 .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap 1604 @*/ 1605 PetscErrorCode DMPlexPartitionLabelClosure(DM dm, DMLabel label) 1606 { 1607 IS rankIS, pointIS; 1608 const PetscInt *ranks, *points; 1609 PetscInt numRanks, numPoints, r, p, c, closureSize; 1610 PetscInt *closure = NULL; 1611 PetscErrorCode ierr; 1612 1613 PetscFunctionBegin; 1614 ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr); 1615 ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr); 1616 ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr); 1617 for (r = 0; r < numRanks; ++r) { 1618 const PetscInt rank = ranks[r]; 1619 1620 ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr); 1621 ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr); 1622 ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr); 1623 for (p = 0; p < numPoints; ++p) { 1624 ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 1625 for (c = 0; c < closureSize*2; c += 2) { 1626 ierr = DMLabelSetValue(label, closure[c], rank);CHKERRQ(ierr); 1627 ierr = DMPlexPartitionLabelClosure_Tree(dm,label,rank,closure[c],PETSC_TRUE,PETSC_TRUE);CHKERRQ(ierr); 1628 } 1629 } 1630 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 1631 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 1632 } 1633 if (closure) {ierr = DMPlexRestoreTransitiveClosure(dm, 0, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);} 1634 ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr); 1635 ierr = ISDestroy(&rankIS);CHKERRQ(ierr); 1636 PetscFunctionReturn(0); 1637 } 1638 1639 /*@ 1640 DMPlexPartitionLabelAdjacency - Add one level of adjacent points to the partition label 1641 1642 Input Parameters: 1643 + dm - The DM 1644 - label - DMLabel assinging ranks to remote roots 1645 1646 Level: developer 1647 1648 .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap 1649 @*/ 1650 PetscErrorCode DMPlexPartitionLabelAdjacency(DM dm, DMLabel label) 1651 { 1652 IS rankIS, pointIS; 1653 const PetscInt *ranks, *points; 1654 PetscInt numRanks, numPoints, r, p, a, adjSize; 1655 PetscInt *adj = NULL; 1656 PetscErrorCode ierr; 1657 1658 PetscFunctionBegin; 1659 ierr = DMLabelGetValueIS(label, &rankIS);CHKERRQ(ierr); 1660 ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr); 1661 ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr); 1662 for (r = 0; r < numRanks; ++r) { 1663 const PetscInt rank = ranks[r]; 1664 1665 ierr = DMLabelGetStratumIS(label, rank, &pointIS);CHKERRQ(ierr); 1666 ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr); 1667 ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr); 1668 for (p = 0; p < numPoints; ++p) { 1669 adjSize = PETSC_DETERMINE; 1670 ierr = DMPlexGetAdjacency(dm, points[p], &adjSize, &adj);CHKERRQ(ierr); 1671 for (a = 0; a < adjSize; ++a) {ierr = DMLabelSetValue(label, adj[a], rank);CHKERRQ(ierr);} 1672 } 1673 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 1674 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 1675 } 1676 ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr); 1677 ierr = ISDestroy(&rankIS);CHKERRQ(ierr); 1678 ierr = PetscFree(adj);CHKERRQ(ierr); 1679 PetscFunctionReturn(0); 1680 } 1681 1682 /*@ 1683 DMPlexPartitionLabelPropagate - Propagate points in a partition label over the point SF 1684 1685 Input Parameters: 1686 + dm - The DM 1687 - label - DMLabel assinging ranks to remote roots 1688 1689 Level: developer 1690 1691 Note: This is required when generating multi-level overlaps to capture 1692 overlap points from non-neighbouring partitions. 1693 1694 .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap 1695 @*/ 1696 PetscErrorCode DMPlexPartitionLabelPropagate(DM dm, DMLabel label) 1697 { 1698 MPI_Comm comm; 1699 PetscMPIInt rank; 1700 PetscSF sfPoint; 1701 DMLabel lblRoots, lblLeaves; 1702 IS rankIS, pointIS; 1703 const PetscInt *ranks; 1704 PetscInt numRanks, r; 1705 PetscErrorCode ierr; 1706 1707 PetscFunctionBegin; 1708 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 1709 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 1710 ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr); 1711 /* Pull point contributions from remote leaves into local roots */ 1712 ierr = DMLabelGather(label, sfPoint, &lblLeaves);CHKERRQ(ierr); 1713 ierr = DMLabelGetValueIS(lblLeaves, &rankIS);CHKERRQ(ierr); 1714 ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr); 1715 ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr); 1716 for (r = 0; r < numRanks; ++r) { 1717 const PetscInt remoteRank = ranks[r]; 1718 if (remoteRank == rank) continue; 1719 ierr = DMLabelGetStratumIS(lblLeaves, remoteRank, &pointIS);CHKERRQ(ierr); 1720 ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr); 1721 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 1722 } 1723 ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr); 1724 ierr = ISDestroy(&rankIS);CHKERRQ(ierr); 1725 ierr = DMLabelDestroy(&lblLeaves);CHKERRQ(ierr); 1726 /* Push point contributions from roots into remote leaves */ 1727 ierr = DMLabelDistribute(label, sfPoint, &lblRoots);CHKERRQ(ierr); 1728 ierr = DMLabelGetValueIS(lblRoots, &rankIS);CHKERRQ(ierr); 1729 ierr = ISGetLocalSize(rankIS, &numRanks);CHKERRQ(ierr); 1730 ierr = ISGetIndices(rankIS, &ranks);CHKERRQ(ierr); 1731 for (r = 0; r < numRanks; ++r) { 1732 const PetscInt remoteRank = ranks[r]; 1733 if (remoteRank == rank) continue; 1734 ierr = DMLabelGetStratumIS(lblRoots, remoteRank, &pointIS);CHKERRQ(ierr); 1735 ierr = DMLabelInsertIS(label, pointIS, remoteRank);CHKERRQ(ierr); 1736 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 1737 } 1738 ierr = ISRestoreIndices(rankIS, &ranks);CHKERRQ(ierr); 1739 ierr = ISDestroy(&rankIS);CHKERRQ(ierr); 1740 ierr = DMLabelDestroy(&lblRoots);CHKERRQ(ierr); 1741 PetscFunctionReturn(0); 1742 } 1743 1744 /*@ 1745 DMPlexPartitionLabelInvert - Create a partition label of remote roots from a local root label 1746 1747 Input Parameters: 1748 + dm - The DM 1749 . rootLabel - DMLabel assinging ranks to local roots 1750 . processSF - A star forest mapping into the local index on each remote rank 1751 1752 Output Parameter: 1753 - leafLabel - DMLabel assinging ranks to remote roots 1754 1755 Note: The rootLabel defines a send pattern by mapping local points to remote target ranks. The 1756 resulting leafLabel is a receiver mapping of remote roots to their parent rank. 1757 1758 Level: developer 1759 1760 .seealso: DMPlexPartitionLabelCreateSF, DMPlexDistribute(), DMPlexCreateOverlap 1761 @*/ 1762 PetscErrorCode DMPlexPartitionLabelInvert(DM dm, DMLabel rootLabel, PetscSF processSF, DMLabel leafLabel) 1763 { 1764 MPI_Comm comm; 1765 PetscMPIInt rank, size; 1766 PetscInt p, n, numNeighbors, ssize, l, nleaves; 1767 PetscSF sfPoint; 1768 PetscSFNode *rootPoints, *leafPoints; 1769 PetscSection rootSection, leafSection; 1770 const PetscSFNode *remote; 1771 const PetscInt *local, *neighbors; 1772 IS valueIS; 1773 PetscErrorCode ierr; 1774 1775 PetscFunctionBegin; 1776 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 1777 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 1778 ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr); 1779 ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr); 1780 1781 /* Convert to (point, rank) and use actual owners */ 1782 ierr = PetscSectionCreate(comm, &rootSection);CHKERRQ(ierr); 1783 ierr = PetscSectionSetChart(rootSection, 0, size);CHKERRQ(ierr); 1784 ierr = DMLabelGetValueIS(rootLabel, &valueIS);CHKERRQ(ierr); 1785 ierr = ISGetLocalSize(valueIS, &numNeighbors);CHKERRQ(ierr); 1786 ierr = ISGetIndices(valueIS, &neighbors);CHKERRQ(ierr); 1787 for (n = 0; n < numNeighbors; ++n) { 1788 PetscInt numPoints; 1789 1790 ierr = DMLabelGetStratumSize(rootLabel, neighbors[n], &numPoints);CHKERRQ(ierr); 1791 ierr = PetscSectionAddDof(rootSection, neighbors[n], numPoints);CHKERRQ(ierr); 1792 } 1793 ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr); 1794 ierr = PetscSectionGetStorageSize(rootSection, &ssize);CHKERRQ(ierr); 1795 ierr = PetscMalloc1(ssize, &rootPoints);CHKERRQ(ierr); 1796 ierr = PetscSFGetGraph(sfPoint, NULL, &nleaves, &local, &remote);CHKERRQ(ierr); 1797 for (n = 0; n < numNeighbors; ++n) { 1798 IS pointIS; 1799 const PetscInt *points; 1800 PetscInt off, numPoints, p; 1801 1802 ierr = PetscSectionGetOffset(rootSection, neighbors[n], &off);CHKERRQ(ierr); 1803 ierr = DMLabelGetStratumIS(rootLabel, neighbors[n], &pointIS);CHKERRQ(ierr); 1804 ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr); 1805 ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr); 1806 for (p = 0; p < numPoints; ++p) { 1807 if (local) {ierr = PetscFindInt(points[p], nleaves, local, &l);CHKERRQ(ierr);} 1808 else {l = -1;} 1809 if (l >= 0) {rootPoints[off+p] = remote[l];} 1810 else {rootPoints[off+p].index = points[p]; rootPoints[off+p].rank = rank;} 1811 } 1812 ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr); 1813 ierr = ISDestroy(&pointIS);CHKERRQ(ierr); 1814 } 1815 ierr = ISRestoreIndices(valueIS, &neighbors);CHKERRQ(ierr); 1816 ierr = ISDestroy(&valueIS);CHKERRQ(ierr); 1817 /* Communicate overlap */ 1818 ierr = PetscSectionCreate(comm, &leafSection);CHKERRQ(ierr); 1819 ierr = DMPlexDistributeData(dm, processSF, rootSection, MPIU_2INT, rootPoints, leafSection, (void**) &leafPoints);CHKERRQ(ierr); 1820 /* Filter remote contributions (ovLeafPoints) into the overlapSF */ 1821 ierr = PetscSectionGetStorageSize(leafSection, &ssize);CHKERRQ(ierr); 1822 for (p = 0; p < ssize; p++) { 1823 ierr = DMLabelSetValue(leafLabel, leafPoints[p].index, leafPoints[p].rank);CHKERRQ(ierr); 1824 } 1825 ierr = PetscFree(rootPoints);CHKERRQ(ierr); 1826 ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr); 1827 ierr = PetscFree(leafPoints);CHKERRQ(ierr); 1828 ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr); 1829 PetscFunctionReturn(0); 1830 } 1831 1832 /*@ 1833 DMPlexPartitionLabelCreateSF - Create a star forest from a label that assigns ranks to points 1834 1835 Input Parameters: 1836 + dm - The DM 1837 . label - DMLabel assinging ranks to remote roots 1838 1839 Output Parameter: 1840 - sf - The star forest communication context encapsulating the defined mapping 1841 1842 Note: The incoming label is a receiver mapping of remote points to their parent rank. 1843 1844 Level: developer 1845 1846 .seealso: DMPlexDistribute(), DMPlexCreateOverlap 1847 @*/ 1848 PetscErrorCode DMPlexPartitionLabelCreateSF(DM dm, DMLabel label, PetscSF *sf) 1849 { 1850 PetscMPIInt rank, size; 1851 PetscInt n, numRemote, p, numPoints, pStart, pEnd, idx = 0; 1852 PetscSFNode *remotePoints; 1853 IS remoteRootIS; 1854 const PetscInt *remoteRoots; 1855 PetscErrorCode ierr; 1856 1857 PetscFunctionBegin; 1858 ierr = MPI_Comm_rank(PetscObjectComm((PetscObject) dm), &rank);CHKERRQ(ierr); 1859 ierr = MPI_Comm_size(PetscObjectComm((PetscObject) dm), &size);CHKERRQ(ierr); 1860 1861 for (numRemote = 0, n = 0; n < size; ++n) { 1862 ierr = DMLabelGetStratumSize(label, n, &numPoints);CHKERRQ(ierr); 1863 numRemote += numPoints; 1864 } 1865 ierr = PetscMalloc1(numRemote, &remotePoints);CHKERRQ(ierr); 1866 /* Put owned points first */ 1867 ierr = DMLabelGetStratumSize(label, rank, &numPoints);CHKERRQ(ierr); 1868 if (numPoints > 0) { 1869 ierr = DMLabelGetStratumIS(label, rank, &remoteRootIS);CHKERRQ(ierr); 1870 ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr); 1871 for (p = 0; p < numPoints; p++) { 1872 remotePoints[idx].index = remoteRoots[p]; 1873 remotePoints[idx].rank = rank; 1874 idx++; 1875 } 1876 ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr); 1877 ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr); 1878 } 1879 /* Now add remote points */ 1880 for (n = 0; n < size; ++n) { 1881 ierr = DMLabelGetStratumSize(label, n, &numPoints);CHKERRQ(ierr); 1882 if (numPoints <= 0 || n == rank) continue; 1883 ierr = DMLabelGetStratumIS(label, n, &remoteRootIS);CHKERRQ(ierr); 1884 ierr = ISGetIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr); 1885 for (p = 0; p < numPoints; p++) { 1886 remotePoints[idx].index = remoteRoots[p]; 1887 remotePoints[idx].rank = n; 1888 idx++; 1889 } 1890 ierr = ISRestoreIndices(remoteRootIS, &remoteRoots);CHKERRQ(ierr); 1891 ierr = ISDestroy(&remoteRootIS);CHKERRQ(ierr); 1892 } 1893 ierr = PetscSFCreate(PetscObjectComm((PetscObject) dm), sf);CHKERRQ(ierr); 1894 ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr); 1895 ierr = PetscSFSetGraph(*sf, pEnd-pStart, numRemote, NULL, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr); 1896 PetscFunctionReturn(0); 1897 } 1898