1 #include <petsc/private/partitionerimpl.h> /*I "petscpartitioner.h" I*/ 2 3 /*@ 4 PetscPartitionerSetType - Builds a particular `PetscPartitioner` 5 6 Collective 7 8 Input Parameters: 9 + part - The `PetscPartitioner` object 10 - name - The kind of partitioner 11 12 Options Database Key: 13 . -petscpartitioner_type <type> - Sets the `PetscPartitioner` type 14 15 Level: intermediate 16 17 Note: 18 .vb 19 PETSCPARTITIONERCHACO - The Chaco partitioner (--download-chaco) 20 PETSCPARTITIONERPARMETIS - The ParMetis partitioner (--download-parmetis) 21 PETSCPARTITIONERSHELL - A shell partitioner implemented by the user 22 PETSCPARTITIONERSIMPLE - A simple partitioner that divides cells into equal, contiguous chunks 23 PETSCPARTITIONERGATHER - Gathers all cells onto process 0 24 .ve 25 26 .seealso: `PetscPartitionerGetType()`, `PetscPartitionerCreate()` 27 @*/ 28 PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name) 29 { 30 PetscErrorCode (*r)(PetscPartitioner); 31 PetscBool match; 32 33 PetscFunctionBegin; 34 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 35 PetscCall(PetscObjectTypeCompare((PetscObject)part, name, &match)); 36 if (match) PetscFunctionReturn(PETSC_SUCCESS); 37 38 PetscCall(PetscPartitionerRegisterAll()); 39 PetscCall(PetscFunctionListFind(PetscPartitionerList, name, &r)); 40 PetscCheck(r, PetscObjectComm((PetscObject)part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name); 41 42 PetscTryTypeMethod(part, destroy); 43 part->noGraph = PETSC_FALSE; 44 PetscCall(PetscMemzero(part->ops, sizeof(*part->ops))); 45 PetscCall(PetscObjectChangeTypeName((PetscObject)part, name)); 46 PetscCall((*r)(part)); 47 PetscFunctionReturn(PETSC_SUCCESS); 48 } 49 50 /*@ 51 PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object. 52 53 Not Collective 54 55 Input Parameter: 56 . part - The PetscPartitioner 57 58 Output Parameter: 59 . name - The PetscPartitioner type name 60 61 Level: intermediate 62 63 .seealso: `PetscPartitionerSetType()`, `PetscPartitionerCreate()` 64 @*/ 65 PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name) 66 { 67 PetscFunctionBegin; 68 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 69 PetscAssertPointer(name, 2); 70 *name = ((PetscObject)part)->type_name; 71 PetscFunctionReturn(PETSC_SUCCESS); 72 } 73 74 /*@ 75 PetscPartitionerViewFromOptions - View a `PetscPartitioner` object based on options in the options database 76 77 Collective 78 79 Input Parameters: 80 + A - the `PetscPartitioner` object 81 . obj - Optional `PetscObject` that provides the options prefix 82 - name - command line option 83 84 Level: intermediate 85 86 Note: 87 See `PetscObjectViewFromOptions()` for the various forms of viewers that may be used 88 89 .seealso: `PetscPartitionerView()`, `PetscObjectViewFromOptions()` 90 @*/ 91 PetscErrorCode PetscPartitionerViewFromOptions(PetscPartitioner A, PetscObject obj, const char name[]) 92 { 93 PetscFunctionBegin; 94 PetscValidHeaderSpecific(A, PETSCPARTITIONER_CLASSID, 1); 95 PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name)); 96 PetscFunctionReturn(PETSC_SUCCESS); 97 } 98 99 /*@ 100 PetscPartitionerView - Views a `PetscPartitioner` 101 102 Collective 103 104 Input Parameters: 105 + part - the `PetscPartitioner` object to view 106 - v - the viewer 107 108 Level: developer 109 110 .seealso: `PetscPartitionerDestroy()` 111 @*/ 112 PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v) 113 { 114 PetscMPIInt size; 115 PetscBool isascii; 116 117 PetscFunctionBegin; 118 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 119 if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)part), &v)); 120 PetscCall(PetscObjectTypeCompare((PetscObject)v, PETSCVIEWERASCII, &isascii)); 121 if (isascii) { 122 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)part), &size)); 123 PetscCall(PetscViewerASCIIPrintf(v, "Graph Partitioner: %d MPI Process%s\n", size, size > 1 ? "es" : "")); 124 PetscCall(PetscViewerASCIIPrintf(v, " type: %s\n", ((PetscObject)part)->type_name)); 125 PetscCall(PetscViewerASCIIPrintf(v, " edge cut: %" PetscInt_FMT "\n", part->edgeCut)); 126 PetscCall(PetscViewerASCIIPrintf(v, " balance: %.2g\n", (double)part->balance)); 127 PetscCall(PetscViewerASCIIPrintf(v, " use vertex weights: %d\n", part->usevwgt)); 128 PetscCall(PetscViewerASCIIPrintf(v, " use edge weights: %d\n", part->useewgt)); 129 } 130 PetscTryTypeMethod(part, view, v); 131 PetscFunctionReturn(PETSC_SUCCESS); 132 } 133 134 static PetscErrorCode PetscPartitionerGetDefaultType(MPI_Comm comm, const char **defaultType) 135 { 136 PetscMPIInt size; 137 138 PetscFunctionBegin; 139 PetscCallMPI(MPI_Comm_size(comm, &size)); 140 if (size == 1) { 141 *defaultType = PETSCPARTITIONERSIMPLE; 142 } else { 143 #if defined(PETSC_HAVE_PARMETIS) 144 *defaultType = PETSCPARTITIONERPARMETIS; 145 #elif defined(PETSC_HAVE_PTSCOTCH) 146 *defaultType = PETSCPARTITIONERPTSCOTCH; 147 #elif defined(PETSC_HAVE_CHACO) 148 *defaultType = PETSCPARTITIONERCHACO; 149 #else 150 *defaultType = PETSCPARTITIONERSIMPLE; 151 #endif 152 } 153 PetscFunctionReturn(PETSC_SUCCESS); 154 } 155 156 /*@ 157 PetscPartitionerSetFromOptions - sets parameters in a `PetscPartitioner` from the options database 158 159 Collective 160 161 Input Parameter: 162 . part - the `PetscPartitioner` object to set options for 163 164 Options Database Keys: 165 + -petscpartitioner_type <type> - Sets the `PetscPartitioner` type; use -help for a list of available types 166 . -petscpartitioner_use_vertex_weights - Uses weights associated with the graph vertices 167 - -petscpartitioner_view_graph - View the graph each time PetscPartitionerPartition is called. Viewer can be customized, see `PetscOptionsGetViewer()` 168 169 Level: developer 170 171 .seealso: `PetscPartitionerView()`, `PetscPartitionerSetType()`, `PetscPartitionerPartition()` 172 @*/ 173 PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part) 174 { 175 const char *currentType = NULL; 176 char name[256]; 177 PetscBool flg; 178 179 PetscFunctionBegin; 180 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 181 PetscObjectOptionsBegin((PetscObject)part); 182 PetscCall(PetscPartitionerGetType(part, ¤tType)); 183 PetscCall(PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, currentType, name, sizeof(name), &flg)); 184 if (flg) PetscCall(PetscPartitionerSetType(part, name)); 185 PetscCall(PetscOptionsBool("-petscpartitioner_use_vertex_weights", "Use vertex weights", "", part->usevwgt, &part->usevwgt, NULL)); 186 PetscCall(PetscOptionsBool("-petscpartitioner_use_edge_weights", "Use edge weights", "", part->useewgt, &part->useewgt, NULL)); 187 PetscTryTypeMethod(part, setfromoptions, PetscOptionsObject); 188 PetscCall(PetscOptionsRestoreViewer(&part->viewer)); 189 PetscCall(PetscOptionsRestoreViewer(&part->viewerGraph)); 190 PetscCall(PetscOptionsGetViewer(((PetscObject)part)->comm, ((PetscObject)part)->options, ((PetscObject)part)->prefix, "-petscpartitioner_view", &part->viewer, NULL, NULL)); 191 PetscCall(PetscOptionsGetViewer(((PetscObject)part)->comm, ((PetscObject)part)->options, ((PetscObject)part)->prefix, "-petscpartitioner_view_graph", &part->viewerGraph, NULL, &part->viewGraph)); 192 /* process any options handlers added with PetscObjectAddOptionsHandler() */ 193 PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)part, PetscOptionsObject)); 194 PetscOptionsEnd(); 195 PetscFunctionReturn(PETSC_SUCCESS); 196 } 197 198 /*@ 199 PetscPartitionerSetUp - Construct data structures for the `PetscPartitioner` 200 201 Collective 202 203 Input Parameter: 204 . part - the `PetscPartitioner` object to setup 205 206 Level: developer 207 208 .seealso: `PetscPartitionerView()`, `PetscPartitionerDestroy()` 209 @*/ 210 PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part) 211 { 212 PetscFunctionBegin; 213 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 214 PetscTryTypeMethod(part, setup); 215 PetscFunctionReturn(PETSC_SUCCESS); 216 } 217 218 /*@ 219 PetscPartitionerReset - Resets data structures for the `PetscPartitioner` 220 221 Collective 222 223 Input Parameter: 224 . part - the `PetscPartitioner` object to reset 225 226 Level: developer 227 228 .seealso: `PetscPartitionerSetUp()`, `PetscPartitionerDestroy()` 229 @*/ 230 PetscErrorCode PetscPartitionerReset(PetscPartitioner part) 231 { 232 PetscFunctionBegin; 233 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 234 PetscTryTypeMethod(part, reset); 235 PetscFunctionReturn(PETSC_SUCCESS); 236 } 237 238 /*@ 239 PetscPartitionerDestroy - Destroys a `PetscPartitioner` object 240 241 Collective 242 243 Input Parameter: 244 . part - the `PetscPartitioner` object to destroy 245 246 Level: developer 247 248 .seealso: `PetscPartitionerView()` 249 @*/ 250 PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part) 251 { 252 PetscFunctionBegin; 253 if (!*part) PetscFunctionReturn(PETSC_SUCCESS); 254 PetscValidHeaderSpecific(*part, PETSCPARTITIONER_CLASSID, 1); 255 256 if (--((PetscObject)*part)->refct > 0) { 257 *part = NULL; 258 PetscFunctionReturn(PETSC_SUCCESS); 259 } 260 ((PetscObject)*part)->refct = 0; 261 262 PetscCall(PetscPartitionerReset(*part)); 263 264 PetscCall(PetscOptionsRestoreViewer(&(*part)->viewer)); 265 PetscCall(PetscOptionsRestoreViewer(&(*part)->viewerGraph)); 266 PetscTryTypeMethod(*part, destroy); 267 PetscCall(PetscHeaderDestroy(part)); 268 PetscFunctionReturn(PETSC_SUCCESS); 269 } 270 271 /*@ 272 PetscPartitionerPartition - Partition a graph 273 274 Collective 275 276 Input Parameters: 277 + part - The `PetscPartitioner` 278 . nparts - Number of partitions 279 . numVertices - Number of vertices in the local part of the graph 280 . start - row pointers for the local part of the graph (CSR style) 281 . adjacency - adjacency list (CSR style) 282 . vertexSection - PetscSection describing the absolute weight of each local vertex (can be `NULL`) 283 . edgeSection - PetscSection describing the absolute weight of each local edge (can be `NULL`) 284 - targetSection - PetscSection describing the absolute weight of each partition (can be `NULL`) 285 286 Output Parameters: 287 + partSection - The `PetscSection` giving the division of points by partition 288 - partition - The list of points by partition 289 290 Options Databasen Keys: 291 + -petscpartitioner_view - View the partitioner information 292 - -petscpartitioner_view_graph - View the graph we are partitioning 293 294 Level: developer 295 296 Notes: 297 The chart of the vertexSection (if present) must contain [0,numVertices), with the number of dofs in the section specifying the absolute weight for each vertex. 298 The chart of the targetSection (if present) must contain [0,nparts), with the number of dofs in the section specifying the absolute weight for each partition. This information must be the same across processes, PETSc does not check it. 299 300 .seealso: `PetscPartitionerCreate()`, `PetscPartitionerSetType()`, `PetscSectionCreate()`, `PetscSectionSetChart()`, `PetscSectionSetDof()` 301 @*/ 302 PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertexSection, PetscSection edgeSection, PetscSection targetSection, PetscSection partSection, IS *partition) 303 { 304 PetscFunctionBegin; 305 PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1); 306 PetscValidLogicalCollectiveInt(part, nparts, 2); 307 PetscCheck(nparts > 0, PetscObjectComm((PetscObject)part), PETSC_ERR_ARG_OUTOFRANGE, "Number of parts must be positive"); 308 PetscCheck(numVertices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices must be non-negative"); 309 if (numVertices && !part->noGraph) { 310 PetscAssertPointer(start, 4); 311 PetscAssertPointer(start + numVertices, 4); 312 if (start[numVertices]) PetscAssertPointer(adjacency, 5); 313 } 314 if (vertexSection) { 315 PetscInt s, e; 316 317 PetscValidHeaderSpecific(vertexSection, PETSC_SECTION_CLASSID, 6); 318 PetscCall(PetscSectionGetChart(vertexSection, &s, &e)); 319 PetscCheck(s <= 0 && e >= numVertices, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid vertexSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")", s, e); 320 } 321 if (edgeSection) { 322 PetscInt s, e; 323 324 PetscValidHeaderSpecific(edgeSection, PETSC_SECTION_CLASSID, 7); 325 PetscCall(PetscSectionGetChart(edgeSection, &s, &e)); 326 PetscCheck(s <= 0 && e >= start[numVertices], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid edgeSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")", s, e); 327 } 328 if (targetSection) { 329 PetscInt s, e; 330 331 PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 8); 332 PetscCall(PetscSectionGetChart(targetSection, &s, &e)); 333 PetscCheck(s <= 0 && e >= nparts, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid targetSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")", s, e); 334 } 335 PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 9); 336 PetscAssertPointer(partition, 10); 337 338 PetscCall(PetscSectionReset(partSection)); 339 PetscCall(PetscSectionSetChart(partSection, 0, nparts)); 340 if (nparts == 1) { /* quick */ 341 PetscCall(PetscSectionSetDof(partSection, 0, numVertices)); 342 PetscCall(ISCreateStride(PetscObjectComm((PetscObject)part), numVertices, 0, 1, partition)); 343 } else PetscUseTypeMethod(part, partition, nparts, numVertices, start, adjacency, vertexSection, edgeSection, targetSection, partSection, partition); 344 PetscCall(PetscSectionSetUp(partSection)); 345 if (part->viewerGraph) { 346 PetscViewer viewer = part->viewerGraph; 347 PetscBool isascii; 348 PetscInt v, i; 349 PetscMPIInt rank; 350 351 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank)); 352 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 353 if (isascii) { 354 PetscCall(PetscViewerASCIIPushSynchronized(viewer)); 355 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %" PetscInt_FMT "\n", rank, numVertices)); 356 for (v = 0; v < numVertices; ++v) { 357 const PetscInt s = start[v]; 358 const PetscInt e = start[v + 1]; 359 360 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d] ", rank)); 361 for (i = s; i < e; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT " ", adjacency[i])); 362 PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%" PetscInt_FMT "-%" PetscInt_FMT ")\n", s, e)); 363 } 364 PetscCall(PetscViewerFlush(viewer)); 365 PetscCall(PetscViewerASCIIPopSynchronized(viewer)); 366 } 367 } 368 if (part->viewer) PetscCall(PetscPartitionerView(part, part->viewer)); 369 PetscFunctionReturn(PETSC_SUCCESS); 370 } 371 372 /*@ 373 PetscPartitionerCreate - Creates an empty `PetscPartitioner` object. The type can then be set with `PetscPartitionerSetType()`. 374 375 Collective 376 377 Input Parameter: 378 . comm - The communicator for the `PetscPartitioner` object 379 380 Output Parameter: 381 . part - The `PetscPartitioner` object 382 383 Level: beginner 384 385 .seealso: `PetscPartitionerSetType()`, `PetscPartitionerDestroy()` 386 @*/ 387 PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part) 388 { 389 PetscPartitioner p; 390 const char *partitionerType = NULL; 391 392 PetscFunctionBegin; 393 PetscAssertPointer(part, 2); 394 *part = NULL; 395 PetscCall(PetscPartitionerInitializePackage()); 396 397 PetscCall(PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView)); 398 PetscCall(PetscPartitionerGetDefaultType(comm, &partitionerType)); 399 PetscCall(PetscPartitionerSetType(p, partitionerType)); 400 401 p->edgeCut = 0; 402 p->balance = 0.0; 403 p->usevwgt = PETSC_TRUE; 404 405 *part = p; 406 PetscFunctionReturn(PETSC_SUCCESS); 407 } 408