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 #undef __FUNCT__ 30 #define __FUNCT__ "DMPlexCreateNeighborCSR" 31 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency) 32 { 33 const PetscInt maxFaceCases = 30; 34 PetscInt numFaceCases = 0; 35 PetscInt numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */ 36 PetscInt *off, *adj; 37 PetscInt *neighborCells = NULL; 38 PetscInt dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell; 39 PetscErrorCode ierr; 40 41 PetscFunctionBegin; 42 /* For parallel partitioning, I think you have to communicate supports */ 43 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 44 cellDim = dim - cellHeight; 45 ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr); 46 ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr); 47 if (cEnd - cStart == 0) { 48 if (numVertices) *numVertices = 0; 49 if (offsets) *offsets = NULL; 50 if (adjacency) *adjacency = NULL; 51 PetscFunctionReturn(0); 52 } 53 numCells = cEnd - cStart; 54 faceDepth = depth - cellHeight; 55 if (dim == depth) { 56 PetscInt f, fStart, fEnd; 57 58 ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr); 59 /* Count neighboring cells */ 60 ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr); 61 for (f = fStart; f < fEnd; ++f) { 62 const PetscInt *support; 63 PetscInt supportSize; 64 ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr); 65 ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr); 66 if (supportSize == 2) { 67 PetscInt numChildren; 68 69 ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr); 70 if (!numChildren) { 71 ++off[support[0]-cStart+1]; 72 ++off[support[1]-cStart+1]; 73 } 74 } 75 } 76 /* Prefix sum */ 77 for (c = 1; c <= numCells; ++c) off[c] += off[c-1]; 78 if (adjacency) { 79 PetscInt *tmp; 80 81 ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr); 82 ierr = PetscMalloc1((numCells+1), &tmp);CHKERRQ(ierr); 83 ierr = PetscMemcpy(tmp, off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr); 84 /* Get neighboring cells */ 85 for (f = fStart; f < fEnd; ++f) { 86 const PetscInt *support; 87 PetscInt supportSize; 88 ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr); 89 ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr); 90 if (supportSize == 2) { 91 PetscInt numChildren; 92 93 ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr); 94 if (!numChildren) { 95 adj[tmp[support[0]-cStart]++] = support[1]; 96 adj[tmp[support[1]-cStart]++] = support[0]; 97 } 98 } 99 } 100 #if defined(PETSC_USE_DEBUG) 101 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); 102 #endif 103 ierr = PetscFree(tmp);CHKERRQ(ierr); 104 } 105 if (numVertices) *numVertices = numCells; 106 if (offsets) *offsets = off; 107 if (adjacency) *adjacency = adj; 108 PetscFunctionReturn(0); 109 } 110 /* Setup face recognition */ 111 if (faceDepth == 1) { 112 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 */ 113 114 for (c = cStart; c < cEnd; ++c) { 115 PetscInt corners; 116 117 ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr); 118 if (!cornersSeen[corners]) { 119 PetscInt nFV; 120 121 if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases"); 122 cornersSeen[corners] = 1; 123 124 ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr); 125 126 numFaceVertices[numFaceCases++] = nFV; 127 } 128 } 129 } 130 ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr); 131 /* Count neighboring cells */ 132 for (cell = cStart; cell < cEnd; ++cell) { 133 PetscInt numNeighbors = PETSC_DETERMINE, n; 134 135 ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr); 136 /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */ 137 for (n = 0; n < numNeighbors; ++n) { 138 PetscInt cellPair[2]; 139 PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE; 140 PetscInt meetSize = 0; 141 const PetscInt *meet = NULL; 142 143 cellPair[0] = cell; cellPair[1] = neighborCells[n]; 144 if (cellPair[0] == cellPair[1]) continue; 145 if (!found) { 146 ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 147 if (meetSize) { 148 PetscInt f; 149 150 for (f = 0; f < numFaceCases; ++f) { 151 if (numFaceVertices[f] == meetSize) { 152 found = PETSC_TRUE; 153 break; 154 } 155 } 156 } 157 ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 158 } 159 if (found) ++off[cell-cStart+1]; 160 } 161 } 162 /* Prefix sum */ 163 for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1]; 164 165 if (adjacency) { 166 ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr); 167 /* Get neighboring cells */ 168 for (cell = cStart; cell < cEnd; ++cell) { 169 PetscInt numNeighbors = PETSC_DETERMINE, n; 170 PetscInt cellOffset = 0; 171 172 ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr); 173 /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */ 174 for (n = 0; n < numNeighbors; ++n) { 175 PetscInt cellPair[2]; 176 PetscBool found = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE; 177 PetscInt meetSize = 0; 178 const PetscInt *meet = NULL; 179 180 cellPair[0] = cell; cellPair[1] = neighborCells[n]; 181 if (cellPair[0] == cellPair[1]) continue; 182 if (!found) { 183 ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 184 if (meetSize) { 185 PetscInt f; 186 187 for (f = 0; f < numFaceCases; ++f) { 188 if (numFaceVertices[f] == meetSize) { 189 found = PETSC_TRUE; 190 break; 191 } 192 } 193 } 194 ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr); 195 } 196 if (found) { 197 adj[off[cell-cStart]+cellOffset] = neighborCells[n]; 198 ++cellOffset; 199 } 200 } 201 } 202 } 203 ierr = PetscFree(neighborCells);CHKERRQ(ierr); 204 if (numVertices) *numVertices = numCells; 205 if (offsets) *offsets = off; 206 if (adjacency) *adjacency = adj; 207 PetscFunctionReturn(0); 208 } 209 210 #undef __FUNCT__ 211 #define __FUNCT__ "DMPlexEnlargePartition" 212 /* Expand the partition by BFS on the adjacency graph */ 213 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection partSection, IS *partition) 214 { 215 PetscHashI h; 216 const PetscInt *points; 217 PetscInt **tmpPoints, *newPoints, totPoints = 0; 218 PetscInt pStart, pEnd, part, q; 219 PetscBool useCone; 220 PetscErrorCode ierr; 221 222 PetscFunctionBegin; 223 PetscHashICreate(h); 224 ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr); 225 ierr = PetscSectionSetChart(partSection, pStart, pEnd);CHKERRQ(ierr); 226 ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr); 227 ierr = PetscMalloc1((pEnd - pStart), &tmpPoints);CHKERRQ(ierr); 228 ierr = DMPlexGetAdjacencyUseCone(dm, &useCone);CHKERRQ(ierr); 229 ierr = DMPlexSetAdjacencyUseCone(dm, PETSC_TRUE);CHKERRQ(ierr); 230 for (part = pStart; part < pEnd; ++part) { 231 PetscInt *adj = NULL; 232 PetscInt numPoints, nP, numNewPoints, off, p, n = 0; 233 234 PetscHashIClear(h); 235 ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr); 236 ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr); 237 /* Add all existing points to h */ 238 for (p = 0; p < numPoints; ++p) { 239 const PetscInt point = points[off+p]; 240 PetscHashIAdd(h, point, 1); 241 } 242 PetscHashISize(h, nP); 243 if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP); 244 /* Add all points in next BFS level */ 245 for (p = 0; p < numPoints; ++p) { 246 const PetscInt point = points[off+p]; 247 PetscInt adjSize = PETSC_DETERMINE, a; 248 249 ierr = DMPlexGetAdjacency(dm, point, &adjSize, &adj);CHKERRQ(ierr); 250 for (a = 0; a < adjSize; ++a) PetscHashIAdd(h, adj[a], 1); 251 } 252 PetscHashISize(h, numNewPoints); 253 ierr = PetscSectionSetDof(partSection, part, numNewPoints);CHKERRQ(ierr); 254 ierr = PetscMalloc1(numNewPoints, &tmpPoints[part]);CHKERRQ(ierr); 255 ierr = PetscHashIGetKeys(h, &n, tmpPoints[part]);CHKERRQ(ierr); 256 ierr = PetscFree(adj);CHKERRQ(ierr); 257 totPoints += numNewPoints; 258 } 259 ierr = DMPlexSetAdjacencyUseCone(dm, useCone);CHKERRQ(ierr); 260 ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr); 261 PetscHashIDestroy(h); 262 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 263 ierr = PetscMalloc1(totPoints, &newPoints);CHKERRQ(ierr); 264 for (part = pStart, q = 0; part < pEnd; ++part) { 265 PetscInt numPoints, p; 266 267 ierr = PetscSectionGetDof(partSection, part, &numPoints);CHKERRQ(ierr); 268 for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p]; 269 ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr); 270 } 271 ierr = PetscFree(tmpPoints);CHKERRQ(ierr); 272 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 273 PetscFunctionReturn(0); 274 } 275 276 #undef __FUNCT__ 277 #define __FUNCT__ "PetscPartitionerRegister" 278 /*@C 279 PetscPartitionerRegister - Adds a new PetscPartitioner implementation 280 281 Not Collective 282 283 Input Parameters: 284 + name - The name of a new user-defined creation routine 285 - create_func - The creation routine itself 286 287 Notes: 288 PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners 289 290 Sample usage: 291 .vb 292 PetscPartitionerRegister("my_part", MyPetscPartitionerCreate); 293 .ve 294 295 Then, your PetscPartitioner type can be chosen with the procedural interface via 296 .vb 297 PetscPartitionerCreate(MPI_Comm, PetscPartitioner *); 298 PetscPartitionerSetType(PetscPartitioner, "my_part"); 299 .ve 300 or at runtime via the option 301 .vb 302 -petscpartitioner_type my_part 303 .ve 304 305 Level: advanced 306 307 .keywords: PetscPartitioner, register 308 .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy() 309 310 @*/ 311 PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner)) 312 { 313 PetscErrorCode ierr; 314 315 PetscFunctionBegin; 316 ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr); 317 PetscFunctionReturn(0); 318 } 319 320 #undef __FUNCT__ 321 #define __FUNCT__ "PetscPartitionerSetType" 322 /*@C 323 PetscPartitionerSetType - Builds a particular PetscPartitioner 324 325 Collective on PetscPartitioner 326 327 Input Parameters: 328 + part - The PetscPartitioner object 329 - name - The kind of partitioner 330 331 Options Database Key: 332 . -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types 333 334 Level: intermediate 335 336 .keywords: PetscPartitioner, set, type 337 .seealso: PetscPartitionerGetType(), PetscPartitionerCreate() 338 @*/ 339 PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name) 340 { 341 PetscErrorCode (*r)(PetscPartitioner); 342 PetscBool match; 343 PetscErrorCode ierr; 344 345 PetscFunctionBegin; 346 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 347 ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr); 348 if (match) PetscFunctionReturn(0); 349 350 if (!PetscPartitionerRegisterAllCalled) {ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);} 351 ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr); 352 if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name); 353 354 if (part->ops->destroy) { 355 ierr = (*part->ops->destroy)(part);CHKERRQ(ierr); 356 part->ops->destroy = NULL; 357 } 358 ierr = (*r)(part);CHKERRQ(ierr); 359 ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr); 360 PetscFunctionReturn(0); 361 } 362 363 #undef __FUNCT__ 364 #define __FUNCT__ "PetscPartitionerGetType" 365 /*@C 366 PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object. 367 368 Not Collective 369 370 Input Parameter: 371 . part - The PetscPartitioner 372 373 Output Parameter: 374 . name - The PetscPartitioner type name 375 376 Level: intermediate 377 378 .keywords: PetscPartitioner, get, type, name 379 .seealso: PetscPartitionerSetType(), PetscPartitionerCreate() 380 @*/ 381 PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name) 382 { 383 PetscErrorCode ierr; 384 385 PetscFunctionBegin; 386 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 387 PetscValidPointer(name, 2); 388 if (!PetscPartitionerRegisterAllCalled) {ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);} 389 *name = ((PetscObject) part)->type_name; 390 PetscFunctionReturn(0); 391 } 392 393 #undef __FUNCT__ 394 #define __FUNCT__ "PetscPartitionerView" 395 /*@C 396 PetscPartitionerView - Views a PetscPartitioner 397 398 Collective on PetscPartitioner 399 400 Input Parameter: 401 + part - the PetscPartitioner object to view 402 - v - the viewer 403 404 Level: developer 405 406 .seealso: PetscPartitionerDestroy() 407 @*/ 408 PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v) 409 { 410 PetscErrorCode ierr; 411 412 PetscFunctionBegin; 413 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 414 if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);} 415 if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);} 416 PetscFunctionReturn(0); 417 } 418 419 #undef __FUNCT__ 420 #define __FUNCT__ "PetscPartitionerViewFromOptions" 421 /* 422 PetscPartitionerViewFromOptions - Processes command line options to determine if/how a PetscPartitioner is to be viewed. 423 424 Collective on PetscPartitioner 425 426 Input Parameters: 427 + part - the PetscPartitioner 428 . prefix - prefix to use for viewing, or NULL 429 - optionname - option to activate viewing 430 431 Level: intermediate 432 433 .keywords: PetscPartitioner, view, options, database 434 .seealso: VecViewFromOptions(), MatViewFromOptions() 435 */ 436 PetscErrorCode PetscPartitionerViewFromOptions(PetscPartitioner part, const char prefix[], const char optionname[]) 437 { 438 PetscViewer viewer; 439 PetscViewerFormat format; 440 PetscBool flg; 441 PetscErrorCode ierr; 442 443 PetscFunctionBegin; 444 if (prefix) {ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) part), prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr);} 445 else {ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) part), ((PetscObject) part)->prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr);} 446 if (flg) { 447 ierr = PetscViewerPushFormat(viewer, format);CHKERRQ(ierr); 448 ierr = PetscPartitionerView(part, viewer);CHKERRQ(ierr); 449 ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr); 450 ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); 451 } 452 PetscFunctionReturn(0); 453 } 454 #undef __FUNCT__ 455 #define __FUNCT__ "PetscPartitionerSetTypeFromOptions_Internal" 456 PetscErrorCode PetscPartitionerSetTypeFromOptions_Internal(PetscPartitioner part) 457 { 458 const char *defaultType; 459 char name[256]; 460 PetscBool flg; 461 PetscErrorCode ierr; 462 463 PetscFunctionBegin; 464 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 465 if (!((PetscObject) part)->type_name) defaultType = PETSCPARTITIONERCHACO; 466 else defaultType = ((PetscObject) part)->type_name; 467 if (!PetscPartitionerRegisterAllCalled) {ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);} 468 469 ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr); 470 ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, 256, &flg);CHKERRQ(ierr); 471 if (flg) { 472 ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr); 473 } else if (!((PetscObject) part)->type_name) { 474 ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr); 475 } 476 ierr = PetscOptionsEnd();CHKERRQ(ierr); 477 PetscFunctionReturn(0); 478 } 479 480 #undef __FUNCT__ 481 #define __FUNCT__ "PetscPartitionerSetFromOptions" 482 /*@ 483 PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database 484 485 Collective on PetscPartitioner 486 487 Input Parameter: 488 . part - the PetscPartitioner object to set options for 489 490 Level: developer 491 492 .seealso: PetscPartitionerView() 493 @*/ 494 PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part) 495 { 496 PetscErrorCode ierr; 497 498 PetscFunctionBegin; 499 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 500 ierr = PetscPartitionerSetTypeFromOptions_Internal(part);CHKERRQ(ierr); 501 502 ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr); 503 if (part->ops->setfromoptions) {ierr = (*part->ops->setfromoptions)(part);CHKERRQ(ierr);} 504 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 505 ierr = PetscObjectProcessOptionsHandlers((PetscObject) part);CHKERRQ(ierr); 506 ierr = PetscOptionsEnd();CHKERRQ(ierr); 507 ierr = PetscPartitionerViewFromOptions(part, NULL, "-petscpartitioner_view");CHKERRQ(ierr); 508 PetscFunctionReturn(0); 509 } 510 511 #undef __FUNCT__ 512 #define __FUNCT__ "PetscPartitionerSetUp" 513 /*@C 514 PetscPartitionerSetUp - Construct data structures for the PetscPartitioner 515 516 Collective on PetscPartitioner 517 518 Input Parameter: 519 . part - the PetscPartitioner object to setup 520 521 Level: developer 522 523 .seealso: PetscPartitionerView(), PetscPartitionerDestroy() 524 @*/ 525 PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part) 526 { 527 PetscErrorCode ierr; 528 529 PetscFunctionBegin; 530 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 531 if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);} 532 PetscFunctionReturn(0); 533 } 534 535 #undef __FUNCT__ 536 #define __FUNCT__ "PetscPartitionerDestroy" 537 /*@ 538 PetscPartitionerDestroy - Destroys a PetscPartitioner object 539 540 Collective on PetscPartitioner 541 542 Input Parameter: 543 . part - the PetscPartitioner object to destroy 544 545 Level: developer 546 547 .seealso: PetscPartitionerView() 548 @*/ 549 PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part) 550 { 551 PetscErrorCode ierr; 552 553 PetscFunctionBegin; 554 if (!*part) PetscFunctionReturn(0); 555 PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1); 556 557 if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);} 558 ((PetscObject) (*part))->refct = 0; 559 560 if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);} 561 ierr = PetscHeaderDestroy(part);CHKERRQ(ierr); 562 PetscFunctionReturn(0); 563 } 564 565 #undef __FUNCT__ 566 #define __FUNCT__ "PetscPartitionerCreate" 567 /*@ 568 PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType(). 569 570 Collective on MPI_Comm 571 572 Input Parameter: 573 . comm - The communicator for the PetscPartitioner object 574 575 Output Parameter: 576 . part - The PetscPartitioner object 577 578 Level: beginner 579 580 .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL 581 @*/ 582 PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part) 583 { 584 PetscPartitioner p; 585 PetscErrorCode ierr; 586 587 PetscFunctionBegin; 588 PetscValidPointer(part, 2); 589 *part = NULL; 590 ierr = PetscFVInitializePackage();CHKERRQ(ierr); 591 592 ierr = PetscHeaderCreate(p, _p_PetscPartitioner, struct _PetscPartitionerOps, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr); 593 ierr = PetscMemzero(p->ops, sizeof(struct _PetscPartitionerOps));CHKERRQ(ierr); 594 595 *part = p; 596 PetscFunctionReturn(0); 597 } 598 599 #undef __FUNCT__ 600 #define __FUNCT__ "PetscPartitionerPartition" 601 /*@ 602 PetscPartitionerPartition - Create a non-overlapping partition of the cells in the mesh 603 604 Collective on DM 605 606 Input Parameters: 607 + part - The PetscPartitioner 608 . dm - The mesh DM 609 - enlarge - Expand each partition with neighbors 610 611 Output Parameters: 612 + partSection - The PetscSection giving the division of points by partition 613 . partition - The list of points by partition 614 . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL 615 - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL 616 617 Note: Instead of cells, points at a given height can be partitioned by calling PetscPartitionerSetPointHeight() 618 619 Level: developer 620 621 .seealso DMPlexDistribute(), PetscPartitionerSetPointHeight(), PetscPartitionerCreate() 622 @*/ 623 PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, DM dm, PetscBool enlarge, PetscSection partSection, IS *partition, PetscSection origPartSection, IS *origPartition) 624 { 625 PetscMPIInt size; 626 PetscErrorCode ierr; 627 628 PetscFunctionBegin; 629 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 630 PetscValidHeaderSpecific(dm, DM_CLASSID, 2); 631 PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4); 632 PetscValidPointer(partition, 5); 633 if (enlarge) {PetscValidHeaderSpecific(origPartSection, PETSC_SECTION_CLASSID, 6);} 634 if (enlarge) {PetscValidPointer(origPartition, 7);} 635 ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr); 636 if (origPartition) *origPartition = NULL; 637 if (size == 1) { 638 PetscInt *points; 639 PetscInt cStart, cEnd, c; 640 641 ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr); 642 ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr); 643 ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr); 644 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 645 ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr); 646 for (c = cStart; c < cEnd; ++c) points[c] = c; 647 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 648 PetscFunctionReturn(0); 649 } 650 if (part->height == 0) { 651 PetscInt numVertices; 652 PetscInt *start = NULL; 653 PetscInt *adjacency = NULL; 654 655 ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr); 656 if (!part->ops->partition) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONGSTATE, "PetscPartitioner has no type"); 657 ierr = (*part->ops->partition)(part, dm, size, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr); 658 if (enlarge) { 659 origPartSection = partSection; 660 *origPartition = *partition; 661 662 ierr = DMPlexEnlargePartition(dm, start, adjacency, origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr); 663 } 664 ierr = PetscFree(start);CHKERRQ(ierr); 665 ierr = PetscFree(adjacency);CHKERRQ(ierr); 666 } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height); 667 PetscFunctionReturn(0); 668 } 669 670 #undef __FUNCT__ 671 #define __FUNCT__ "PetscPartitionerDestroy_Shell" 672 PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part) 673 { 674 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 675 PetscErrorCode ierr; 676 677 PetscFunctionBegin; 678 ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr); 679 ierr = ISDestroy(&p->partition);CHKERRQ(ierr); 680 ierr = PetscFree(p);CHKERRQ(ierr); 681 PetscFunctionReturn(0); 682 } 683 684 #undef __FUNCT__ 685 #define __FUNCT__ "PetscPartitionerView_Shell_Ascii" 686 PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer) 687 { 688 PetscViewerFormat format; 689 PetscErrorCode ierr; 690 691 PetscFunctionBegin; 692 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 693 ierr = PetscViewerASCIIPrintf(viewer, "Shell Graph Partitioner:\n");CHKERRQ(ierr); 694 PetscFunctionReturn(0); 695 } 696 697 #undef __FUNCT__ 698 #define __FUNCT__ "PetscPartitionerView_Shell" 699 PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer) 700 { 701 PetscBool iascii; 702 PetscErrorCode ierr; 703 704 PetscFunctionBegin; 705 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 706 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 707 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 708 if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);} 709 PetscFunctionReturn(0); 710 } 711 712 #undef __FUNCT__ 713 #define __FUNCT__ "PetscPartitionerPartition_Shell" 714 PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) 715 { 716 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 717 PetscInt np; 718 PetscErrorCode ierr; 719 720 PetscFunctionBegin; 721 ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr); 722 if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np); 723 ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr); 724 if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np); 725 ierr = PetscSectionCopy(p->section, partSection);CHKERRQ(ierr); 726 *partition = p->partition; 727 ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr); 728 PetscFunctionReturn(0); 729 } 730 731 #undef __FUNCT__ 732 #define __FUNCT__ "PetscPartitionerInitialize_Shell" 733 PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part) 734 { 735 PetscFunctionBegin; 736 part->ops->view = PetscPartitionerView_Shell; 737 part->ops->destroy = PetscPartitionerDestroy_Shell; 738 part->ops->partition = PetscPartitionerPartition_Shell; 739 PetscFunctionReturn(0); 740 } 741 742 /*MC 743 PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object 744 745 Level: intermediate 746 747 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() 748 M*/ 749 750 #undef __FUNCT__ 751 #define __FUNCT__ "PetscPartitionerCreate_Shell" 752 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part) 753 { 754 PetscPartitioner_Shell *p; 755 PetscErrorCode ierr; 756 757 PetscFunctionBegin; 758 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 759 ierr = PetscNewLog(part, &p);CHKERRQ(ierr); 760 part->data = p; 761 762 ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr); 763 PetscFunctionReturn(0); 764 } 765 766 #undef __FUNCT__ 767 #define __FUNCT__ "PetscPartitionerShellSetPartition" 768 /*@C 769 PetscPartitionerShellSetPartition - Set an artifical partition for a mesh 770 771 Collective on DM 772 773 Input Parameters: 774 + part - The PetscPartitioner 775 . dm - The mesh DM 776 - enlarge - Expand each partition with neighbors 777 778 Level: developer 779 780 .seealso DMPlexDistribute(), PetscPartitionerCreate() 781 @*/ 782 PetscErrorCode PetscPartitionerShellSetPartition(PetscPartitioner part, PetscInt numProcs, const PetscInt sizes[], const PetscInt points[]) 783 { 784 PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data; 785 PetscInt proc, numPoints; 786 PetscErrorCode ierr; 787 788 PetscFunctionBegin; 789 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 790 if (sizes) {PetscValidPointer(sizes, 3);} 791 if (sizes) {PetscValidPointer(points, 4);} 792 ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr); 793 ierr = ISDestroy(&p->partition);CHKERRQ(ierr); 794 ierr = PetscSectionCreate(PetscObjectComm((PetscObject) part), &p->section);CHKERRQ(ierr); 795 ierr = PetscSectionSetChart(p->section, 0, numProcs);CHKERRQ(ierr); 796 if (sizes) { 797 for (proc = 0; proc < numProcs; ++proc) { 798 ierr = PetscSectionSetDof(p->section, proc, sizes[proc]);CHKERRQ(ierr); 799 } 800 } 801 ierr = PetscSectionSetUp(p->section);CHKERRQ(ierr); 802 ierr = PetscSectionGetStorageSize(p->section, &numPoints);CHKERRQ(ierr); 803 ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), numPoints, points, PETSC_COPY_VALUES, &p->partition);CHKERRQ(ierr); 804 PetscFunctionReturn(0); 805 } 806 807 #undef __FUNCT__ 808 #define __FUNCT__ "PetscPartitionerDestroy_Chaco" 809 PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part) 810 { 811 PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data; 812 PetscErrorCode ierr; 813 814 PetscFunctionBegin; 815 ierr = PetscFree(p);CHKERRQ(ierr); 816 PetscFunctionReturn(0); 817 } 818 819 #undef __FUNCT__ 820 #define __FUNCT__ "PetscPartitionerView_Chaco_Ascii" 821 PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer) 822 { 823 PetscViewerFormat format; 824 PetscErrorCode ierr; 825 826 PetscFunctionBegin; 827 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 828 ierr = PetscViewerASCIIPrintf(viewer, "Chaco Graph Partitioner:\n");CHKERRQ(ierr); 829 PetscFunctionReturn(0); 830 } 831 832 #undef __FUNCT__ 833 #define __FUNCT__ "PetscPartitionerView_Chaco" 834 PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer) 835 { 836 PetscBool iascii; 837 PetscErrorCode ierr; 838 839 PetscFunctionBegin; 840 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 841 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 842 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 843 if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);} 844 PetscFunctionReturn(0); 845 } 846 847 #if defined(PETSC_HAVE_CHACO) 848 #if defined(PETSC_HAVE_UNISTD_H) 849 #include <unistd.h> 850 #endif 851 /* Chaco does not have an include file */ 852 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts, 853 float *ewgts, float *x, float *y, float *z, char *outassignname, 854 char *outfilename, short *assignment, int architecture, int ndims_tot, 855 int mesh_dims[3], double *goal, int global_method, int local_method, 856 int rqi_flag, int vmax, int ndims, double eigtol, long seed); 857 858 extern int FREE_GRAPH; 859 #endif 860 861 #undef __FUNCT__ 862 #define __FUNCT__ "PetscPartitionerPartition_Chaco" 863 PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) 864 { 865 #if defined(PETSC_HAVE_CHACO) 866 enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3}; 867 MPI_Comm comm; 868 int nvtxs = numVertices; /* number of vertices in full graph */ 869 int *vwgts = NULL; /* weights for all vertices */ 870 float *ewgts = NULL; /* weights for all edges */ 871 float *x = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */ 872 char *outassignname = NULL; /* name of assignment output file */ 873 char *outfilename = NULL; /* output file name */ 874 int architecture = 1; /* 0 => hypercube, d => d-dimensional mesh */ 875 int ndims_tot = 0; /* total number of cube dimensions to divide */ 876 int mesh_dims[3]; /* dimensions of mesh of processors */ 877 double *goal = NULL; /* desired set sizes for each set */ 878 int global_method = 1; /* global partitioning algorithm */ 879 int local_method = 1; /* local partitioning algorithm */ 880 int rqi_flag = 0; /* should I use RQI/Symmlq eigensolver? */ 881 int vmax = 200; /* how many vertices to coarsen down to? */ 882 int ndims = 1; /* number of eigenvectors (2^d sets) */ 883 double eigtol = 0.001; /* tolerance on eigenvectors */ 884 long seed = 123636512; /* for random graph mutations */ 885 short int *assignment; /* Output partition */ 886 int fd_stdout, fd_pipe[2]; 887 PetscInt *points; 888 int i, v, p; 889 PetscErrorCode ierr; 890 891 PetscFunctionBegin; 892 ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr); 893 if (!numVertices) { 894 ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); 895 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 896 ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 897 PetscFunctionReturn(0); 898 } 899 FREE_GRAPH = 0; /* Do not let Chaco free my memory */ 900 for (i = 0; i < start[numVertices]; ++i) ++adjacency[i]; 901 902 if (global_method == INERTIAL_METHOD) { 903 /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */ 904 SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported"); 905 } 906 mesh_dims[0] = nparts; 907 mesh_dims[1] = 1; 908 mesh_dims[2] = 1; 909 ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr); 910 /* Chaco outputs to stdout. We redirect this to a buffer. */ 911 /* TODO: check error codes for UNIX calls */ 912 #if defined(PETSC_HAVE_UNISTD_H) 913 { 914 int piperet; 915 piperet = pipe(fd_pipe); 916 if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe"); 917 fd_stdout = dup(1); 918 close(1); 919 dup2(fd_pipe[1], 1); 920 } 921 #endif 922 ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename, 923 assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag, 924 vmax, ndims, eigtol, seed); 925 #if defined(PETSC_HAVE_UNISTD_H) 926 { 927 char msgLog[10000]; 928 int count; 929 930 fflush(stdout); 931 count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char)); 932 if (count < 0) count = 0; 933 msgLog[count] = 0; 934 close(1); 935 dup2(fd_stdout, 1); 936 close(fd_stdout); 937 close(fd_pipe[0]); 938 close(fd_pipe[1]); 939 if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog); 940 } 941 #endif 942 /* Convert to PetscSection+IS */ 943 ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); 944 for (v = 0; v < nvtxs; ++v) { 945 ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr); 946 } 947 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 948 ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr); 949 for (p = 0, i = 0; p < nparts; ++p) { 950 for (v = 0; v < nvtxs; ++v) { 951 if (assignment[v] == p) points[i++] = v; 952 } 953 } 954 if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs); 955 ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 956 if (global_method == INERTIAL_METHOD) { 957 /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */ 958 } 959 ierr = PetscFree(assignment);CHKERRQ(ierr); 960 for (i = 0; i < start[numVertices]; ++i) --adjacency[i]; 961 PetscFunctionReturn(0); 962 #else 963 SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco."); 964 #endif 965 } 966 967 #undef __FUNCT__ 968 #define __FUNCT__ "PetscPartitionerInitialize_Chaco" 969 PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part) 970 { 971 PetscFunctionBegin; 972 part->ops->view = PetscPartitionerView_Chaco; 973 part->ops->destroy = PetscPartitionerDestroy_Chaco; 974 part->ops->partition = PetscPartitionerPartition_Chaco; 975 PetscFunctionReturn(0); 976 } 977 978 /*MC 979 PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library 980 981 Level: intermediate 982 983 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() 984 M*/ 985 986 #undef __FUNCT__ 987 #define __FUNCT__ "PetscPartitionerCreate_Chaco" 988 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part) 989 { 990 PetscPartitioner_Chaco *p; 991 PetscErrorCode ierr; 992 993 PetscFunctionBegin; 994 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 995 ierr = PetscNewLog(part, &p);CHKERRQ(ierr); 996 part->data = p; 997 998 ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr); 999 ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr); 1000 PetscFunctionReturn(0); 1001 } 1002 1003 #undef __FUNCT__ 1004 #define __FUNCT__ "PetscPartitionerDestroy_ParMetis" 1005 PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part) 1006 { 1007 PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data; 1008 PetscErrorCode ierr; 1009 1010 PetscFunctionBegin; 1011 ierr = PetscFree(p);CHKERRQ(ierr); 1012 PetscFunctionReturn(0); 1013 } 1014 1015 #undef __FUNCT__ 1016 #define __FUNCT__ "PetscPartitionerView_ParMetis_Ascii" 1017 PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer) 1018 { 1019 PetscViewerFormat format; 1020 PetscErrorCode ierr; 1021 1022 PetscFunctionBegin; 1023 ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr); 1024 ierr = PetscViewerASCIIPrintf(viewer, "ParMetis Graph Partitioner:\n");CHKERRQ(ierr); 1025 PetscFunctionReturn(0); 1026 } 1027 1028 #undef __FUNCT__ 1029 #define __FUNCT__ "PetscPartitionerView_ParMetis" 1030 PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer) 1031 { 1032 PetscBool iascii; 1033 PetscErrorCode ierr; 1034 1035 PetscFunctionBegin; 1036 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 1037 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1038 ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 1039 if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);} 1040 PetscFunctionReturn(0); 1041 } 1042 1043 #if defined(PETSC_HAVE_PARMETIS) 1044 #include <parmetis.h> 1045 #endif 1046 1047 #undef __FUNCT__ 1048 #define __FUNCT__ "PetscPartitionerPartition_ParMetis" 1049 PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition) 1050 { 1051 #if defined(PETSC_HAVE_PARMETIS) 1052 MPI_Comm comm; 1053 PetscInt nvtxs = numVertices; /* The number of vertices in full graph */ 1054 PetscInt *vtxdist; /* Distribution of vertices across processes */ 1055 PetscInt *xadj = start; /* Start of edge list for each vertex */ 1056 PetscInt *adjncy = adjacency; /* Edge lists for all vertices */ 1057 PetscInt *vwgt = NULL; /* Vertex weights */ 1058 PetscInt *adjwgt = NULL; /* Edge weights */ 1059 PetscInt wgtflag = 0; /* Indicates which weights are present */ 1060 PetscInt numflag = 0; /* Indicates initial offset (0 or 1) */ 1061 PetscInt ncon = 1; /* The number of weights per vertex */ 1062 PetscReal *tpwgts; /* The fraction of vertex weights assigned to each partition */ 1063 PetscReal *ubvec; /* The balance intolerance for vertex weights */ 1064 PetscInt options[5]; /* Options */ 1065 /* Outputs */ 1066 PetscInt edgeCut; /* The number of edges cut by the partition */ 1067 PetscInt *assignment, *points; 1068 PetscMPIInt rank, p, v, i; 1069 PetscErrorCode ierr; 1070 1071 PetscFunctionBegin; 1072 ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr); 1073 ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr); 1074 options[0] = 0; /* Use all defaults */ 1075 /* Calculate vertex distribution */ 1076 ierr = PetscMalloc4(nparts+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment);CHKERRQ(ierr); 1077 vtxdist[0] = 0; 1078 ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr); 1079 for (p = 2; p <= nparts; ++p) { 1080 vtxdist[p] += vtxdist[p-1]; 1081 } 1082 /* Calculate weights */ 1083 for (p = 0; p < nparts; ++p) { 1084 tpwgts[p] = 1.0/nparts; 1085 } 1086 ubvec[0] = 1.05; 1087 1088 if (nparts == 1) { 1089 ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt)); 1090 } else { 1091 if (vtxdist[1] == vtxdist[nparts]) { 1092 if (!rank) { 1093 PetscStackPush("METIS_PartGraphKway"); 1094 ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment); 1095 PetscStackPop; 1096 if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()"); 1097 } 1098 } else { 1099 PetscStackPush("ParMETIS_V3_PartKway"); 1100 ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm); 1101 PetscStackPop; 1102 if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()"); 1103 } 1104 } 1105 /* Convert to PetscSection+IS */ 1106 ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr); 1107 for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);} 1108 ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr); 1109 ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr); 1110 for (p = 0, i = 0; p < nparts; ++p) { 1111 for (v = 0; v < nvtxs; ++v) { 1112 if (assignment[v] == p) points[i++] = v; 1113 } 1114 } 1115 if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs); 1116 ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 1117 ierr = PetscFree4(vtxdist,tpwgts,ubvec,assignment);CHKERRQ(ierr); 1118 #else 1119 SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis."); 1120 #endif 1121 PetscFunctionReturn(0); 1122 } 1123 1124 #undef __FUNCT__ 1125 #define __FUNCT__ "PetscPartitionerInitialize_ParMetis" 1126 PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part) 1127 { 1128 PetscFunctionBegin; 1129 part->ops->view = PetscPartitionerView_ParMetis; 1130 part->ops->destroy = PetscPartitionerDestroy_ParMetis; 1131 part->ops->partition = PetscPartitionerPartition_ParMetis; 1132 PetscFunctionReturn(0); 1133 } 1134 1135 /*MC 1136 PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMetis library 1137 1138 Level: intermediate 1139 1140 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType() 1141 M*/ 1142 1143 #undef __FUNCT__ 1144 #define __FUNCT__ "PetscPartitionerCreate_ParMetis" 1145 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part) 1146 { 1147 PetscPartitioner_ParMetis *p; 1148 PetscErrorCode ierr; 1149 1150 PetscFunctionBegin; 1151 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 1152 ierr = PetscNewLog(part, &p);CHKERRQ(ierr); 1153 part->data = p; 1154 1155 ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr); 1156 ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr); 1157 PetscFunctionReturn(0); 1158 } 1159 1160 #undef __FUNCT__ 1161 #define __FUNCT__ "DMPlexGetPartitioner" 1162 /*@ 1163 DMPlexGetPartitioner - Get the mesh partitioner 1164 1165 Not collective 1166 1167 Input Parameter: 1168 . dm - The DM 1169 1170 Output Parameter: 1171 . part - The PetscPartitioner 1172 1173 Level: developer 1174 1175 .seealso DMPlexDistribute(), PetscPartitionerCreate() 1176 @*/ 1177 PetscErrorCode DMPlexGetPartitioner(DM dm, PetscPartitioner *part) 1178 { 1179 DM_Plex *mesh = (DM_Plex *) dm->data; 1180 1181 PetscFunctionBegin; 1182 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1183 PetscValidPointer(part, 2); 1184 *part = mesh->partitioner; 1185 PetscFunctionReturn(0); 1186 } 1187 1188 #undef __FUNCT__ 1189 #define __FUNCT__ "DMPlexMarkTreeClosure" 1190 static PetscErrorCode DMPlexMarkTreeClosure(DM dm, PetscSegBuffer segpart, PetscBT bt, PetscInt point, PetscInt *partSize) 1191 { 1192 PetscInt parent, closureSize, *closure = NULL, i, pStart, pEnd; 1193 PetscErrorCode ierr; 1194 1195 PetscFunctionBegin; 1196 ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr); 1197 if (parent == point) PetscFunctionReturn(0); 1198 ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); 1199 ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 1200 for (i = 0; i < closureSize; i++) { 1201 PetscInt cpoint = closure[2*i]; 1202 1203 if (!PetscBTLookupSet(bt,cpoint-pStart)) { 1204 PetscInt *PETSC_RESTRICT pt; 1205 (*partSize)++; 1206 ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr); 1207 *pt = cpoint; 1208 } 1209 ierr = DMPlexMarkTreeClosure(dm,segpart,bt,cpoint,partSize);CHKERRQ(ierr); 1210 } 1211 ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr); 1212 PetscFunctionReturn(0); 1213 } 1214 1215 #undef __FUNCT__ 1216 #define __FUNCT__ "DMPlexCreatePartitionClosure" 1217 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition) 1218 { 1219 /* const PetscInt height = 0; */ 1220 const PetscInt *partArray; 1221 PetscInt *allPoints, *packPoints; 1222 PetscInt rStart, rEnd, rank, pStart, pEnd, newSize; 1223 PetscErrorCode ierr; 1224 PetscBT bt; 1225 PetscSegBuffer segpack,segpart; 1226 1227 PetscFunctionBegin; 1228 ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr); 1229 ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr); 1230 ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr); 1231 ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr); 1232 ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr); 1233 ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr); 1234 ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr); 1235 ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr); 1236 for (rank = rStart; rank < rEnd; ++rank) { 1237 PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints; 1238 1239 ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr); 1240 ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr); 1241 for (p = 0; p < numPoints; ++p) { 1242 PetscInt point = partArray[offset+p], closureSize, c; 1243 PetscInt *closure = NULL; 1244 1245 /* TODO Include support for height > 0 case */ 1246 ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 1247 for (c=0; c<closureSize; c++) { 1248 PetscInt cpoint = closure[c*2]; 1249 if (!PetscBTLookupSet(bt,cpoint-pStart)) { 1250 PetscInt *PETSC_RESTRICT pt; 1251 partSize++; 1252 ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr); 1253 *pt = cpoint; 1254 } 1255 ierr = DMPlexMarkTreeClosure(dm,segpart,bt,cpoint,&partSize);CHKERRQ(ierr); 1256 } 1257 ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr); 1258 } 1259 ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr); 1260 ierr = PetscSegBufferGetInts(segpack,partSize,&placePoints);CHKERRQ(ierr); 1261 ierr = PetscSegBufferExtractTo(segpart,placePoints);CHKERRQ(ierr); 1262 ierr = PetscSortInt(partSize,placePoints);CHKERRQ(ierr); 1263 for (p=0; p<partSize; p++) {ierr = PetscBTClear(bt,placePoints[p]-pStart);CHKERRQ(ierr);} 1264 } 1265 ierr = PetscBTDestroy(&bt);CHKERRQ(ierr); 1266 ierr = PetscSegBufferDestroy(&segpart);CHKERRQ(ierr); 1267 1268 ierr = PetscSectionSetUp(*section);CHKERRQ(ierr); 1269 ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr); 1270 ierr = PetscMalloc1(newSize, &allPoints);CHKERRQ(ierr); 1271 1272 ierr = PetscSegBufferExtractInPlace(segpack,&packPoints);CHKERRQ(ierr); 1273 for (rank = rStart; rank < rEnd; ++rank) { 1274 PetscInt numPoints, offset; 1275 1276 ierr = PetscSectionGetDof(*section, rank, &numPoints);CHKERRQ(ierr); 1277 ierr = PetscSectionGetOffset(*section, rank, &offset);CHKERRQ(ierr); 1278 ierr = PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));CHKERRQ(ierr); 1279 packPoints += numPoints; 1280 } 1281 1282 ierr = PetscSegBufferDestroy(&segpack);CHKERRQ(ierr); 1283 ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr); 1284 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr); 1285 PetscFunctionReturn(0); 1286 } 1287