Actual source code: partition.c

  1: #include <petsc/private/matimpl.h>

  3: /* Logging support */
  4: PetscClassId MAT_PARTITIONING_CLASSID;

  6: /*
  7:    Simplest partitioning, keeps the current partitioning.
  8: */
  9: static PetscErrorCode MatPartitioningApply_Current(MatPartitioning part, IS *partitioning)
 10: {
 11:   PetscInt    m;
 12:   PetscMPIInt rank, size;

 14:   PetscFunctionBegin;
 15:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)part), &size));
 16:   if (part->n != size) {
 17:     const char *prefix;
 18:     PetscCall(PetscObjectGetOptionsPrefix((PetscObject)part, &prefix));
 19:     SETERRQ(PetscObjectComm((PetscObject)part), PETSC_ERR_SUP, "This is the DEFAULT NO-OP partitioner, it currently only supports one domain per processor\nuse -%smat_partitioning_type parmetis or chaco or ptscotch for more than one subdomain per processor", prefix ? prefix : "");
 20:   }
 21:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)part), &rank));

 23:   PetscCall(MatGetLocalSize(part->adj, &m, NULL));
 24:   PetscCall(ISCreateStride(PetscObjectComm((PetscObject)part), m, rank, 0, partitioning));
 25:   PetscFunctionReturn(PETSC_SUCCESS);
 26: }

 28: /*
 29:    partition an index to rebalance the computation
 30: */
 31: static PetscErrorCode MatPartitioningApply_Average(MatPartitioning part, IS *partitioning)
 32: {
 33:   PetscInt m, M, nparts, *indices, r, d, *parts, i, start, end, loc;

 35:   PetscFunctionBegin;
 36:   PetscCall(MatGetSize(part->adj, &M, NULL));
 37:   PetscCall(MatGetLocalSize(part->adj, &m, NULL));
 38:   nparts = part->n;
 39:   PetscCall(PetscMalloc1(nparts, &parts));
 40:   d = M / nparts;
 41:   for (i = 0; i < nparts; i++) parts[i] = d;
 42:   r = M % nparts;
 43:   for (i = 0; i < r; i++) parts[i] += 1;
 44:   for (i = 1; i < nparts; i++) parts[i] += parts[i - 1];
 45:   PetscCall(PetscMalloc1(m, &indices));
 46:   PetscCall(MatGetOwnershipRange(part->adj, &start, &end));
 47:   for (i = start; i < end; i++) {
 48:     PetscCall(PetscFindInt(i, nparts, parts, &loc));
 49:     if (loc < 0) loc = -(loc + 1);
 50:     else loc = loc + 1;
 51:     indices[i - start] = loc;
 52:   }
 53:   PetscCall(PetscFree(parts));
 54:   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)part), m, indices, PETSC_OWN_POINTER, partitioning));
 55:   PetscFunctionReturn(PETSC_SUCCESS);
 56: }

 58: static PetscErrorCode MatPartitioningApply_Square(MatPartitioning part, IS *partitioning)
 59: {
 60:   PetscInt    cell, n, N, p, rstart, rend, *color;
 61:   PetscMPIInt size;

 63:   PetscFunctionBegin;
 64:   PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)part), &size));
 65:   PetscCheck(part->n == size, PetscObjectComm((PetscObject)part), PETSC_ERR_SUP, "Currently only supports one domain per processor");
 66:   p = (PetscInt)PetscSqrtReal((PetscReal)part->n);
 67:   PetscCheck(p * p == part->n, PetscObjectComm((PetscObject)part), PETSC_ERR_SUP, "Square partitioning requires \"perfect square\" number of domains");

 69:   PetscCall(MatGetSize(part->adj, &N, NULL));
 70:   n = (PetscInt)PetscSqrtReal((PetscReal)N);
 71:   PetscCheck(n * n == N, PetscObjectComm((PetscObject)part), PETSC_ERR_SUP, "Square partitioning requires square domain");
 72:   PetscCheck(n % p == 0, PETSC_COMM_SELF, PETSC_ERR_SUP, "Square partitioning requires p to divide n");
 73:   PetscCall(MatGetOwnershipRange(part->adj, &rstart, &rend));
 74:   PetscCall(PetscMalloc1(rend - rstart, &color));
 75:   /* for (int cell=rstart; cell<rend; cell++) color[cell-rstart] = ((cell%n) < (n/2)) + 2 * ((cell/n) < (n/2)); */
 76:   for (cell = rstart; cell < rend; cell++) color[cell - rstart] = ((cell % n) / (n / p)) + p * ((cell / n) / (n / p));
 77:   PetscCall(ISCreateGeneral(PetscObjectComm((PetscObject)part), rend - rstart, color, PETSC_OWN_POINTER, partitioning));
 78:   PetscFunctionReturn(PETSC_SUCCESS);
 79: }

 81: PETSC_EXTERN PetscErrorCode MatPartitioningCreate_Current(MatPartitioning part)
 82: {
 83:   PetscFunctionBegin;
 84:   part->ops->apply   = MatPartitioningApply_Current;
 85:   part->ops->view    = NULL;
 86:   part->ops->destroy = NULL;
 87:   PetscFunctionReturn(PETSC_SUCCESS);
 88: }

 90: PETSC_EXTERN PetscErrorCode MatPartitioningCreate_Average(MatPartitioning part)
 91: {
 92:   PetscFunctionBegin;
 93:   part->ops->apply   = MatPartitioningApply_Average;
 94:   part->ops->view    = NULL;
 95:   part->ops->destroy = NULL;
 96:   PetscFunctionReturn(PETSC_SUCCESS);
 97: }

 99: PETSC_EXTERN PetscErrorCode MatPartitioningCreate_Square(MatPartitioning part)
100: {
101:   PetscFunctionBegin;
102:   part->ops->apply   = MatPartitioningApply_Square;
103:   part->ops->view    = NULL;
104:   part->ops->destroy = NULL;
105:   PetscFunctionReturn(PETSC_SUCCESS);
106: }

108: /* gets as input the "sizes" array computed by ParMetis_*_NodeND and returns
109:        seps[  0 :         2*p) : the start and end node of each subdomain
110:        seps[2*p : 2*p+2*(p-1)) : the start and end node of each separator
111:      levels[  0 :         p-1) : level in the tree for each separator (-1 root, -2 and -3 first level and so on)
112:    The arrays must be large enough
113: */
114: PETSC_INTERN PetscErrorCode MatPartitioningSizesToSep_Private(PetscInt p, PetscInt sizes[], PetscInt seps[], PetscInt level[])
115: {
116:   PetscInt l2p, i, pTree, pStartTree;

118:   PetscFunctionBegin;
119:   l2p = PetscLog2Real(p);
120:   PetscCheck(!(l2p - (PetscInt)PetscLog2Real(p)), PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "%" PetscInt_FMT " is not a power of 2", p);
121:   if (!p) PetscFunctionReturn(PETSC_SUCCESS);
122:   PetscCall(PetscArrayzero(seps, 2 * p - 2));
123:   PetscCall(PetscArrayzero(level, p - 1));
124:   seps[2 * p - 2] = sizes[2 * p - 2];
125:   pTree           = p;
126:   pStartTree      = 0;
127:   while (pTree != 1) {
128:     for (i = pStartTree; i < pStartTree + pTree; i++) {
129:       seps[i] += sizes[i];
130:       seps[pStartTree + pTree + (i - pStartTree) / 2] += seps[i];
131:     }
132:     pStartTree += pTree;
133:     pTree = pTree / 2;
134:   }
135:   seps[2 * p - 2] -= sizes[2 * p - 2];

137:   pStartTree = 2 * p - 2;
138:   pTree      = 1;
139:   while (pStartTree > 0) {
140:     for (i = pStartTree; i < pStartTree + pTree; i++) {
141:       PetscInt k = 2 * i - (pStartTree + 2 * pTree);
142:       PetscInt n = seps[k + 1];

144:       seps[k + 1]  = seps[i] - sizes[k + 1];
145:       seps[k]      = seps[k + 1] + sizes[k + 1] - n - sizes[k];
146:       level[i - p] = -pTree - i + pStartTree;
147:     }
148:     pTree *= 2;
149:     pStartTree -= pTree;
150:   }
151:   /* I know there should be a formula */
152:   PetscCall(PetscSortIntWithArrayPair(p - 1, seps + p, sizes + p, level));
153:   for (i = 2 * p - 2; i >= 0; i--) {
154:     seps[2 * i]     = seps[i];
155:     seps[2 * i + 1] = seps[i] + PetscMax(sizes[i] - 1, 0);
156:   }
157:   PetscFunctionReturn(PETSC_SUCCESS);
158: }

160: PetscFunctionList MatPartitioningList              = NULL;
161: PetscBool         MatPartitioningRegisterAllCalled = PETSC_FALSE;

163: PetscFunctionList MatMeshToCellGraphList              = NULL;
164: PetscBool         MatMeshToCellGraphRegisterAllCalled = PETSC_FALSE;

166: /*@C
167:   MatPartitioningRegister - Adds a new sparse matrix partitioning to the  matrix package.

169:   Not Collective, No Fortran Support

171:   Input Parameters:
172: + sname    - name of partitioning (for example `MATPARTITIONINGCURRENT`) or `MATPARTITIONINGPARMETIS`
173: - function - function pointer that creates the partitioning type

175:   Level: developer

177:   Example Usage:
178: .vb
179:    MatPartitioningRegister("my_part", MyPartCreate);
180: .ve

182:   Then, your partitioner can be chosen with the procedural interface via `MatPartitioningSetType(part, "my_part")` or at runtime via the option
183:   `-mat_partitioning_type my_part`

185: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningCreate()`, `MatPartitioningRegisterDestroy()`, `MatPartitioningRegisterAll()`
186: @*/
187: PetscErrorCode MatPartitioningRegister(const char sname[], PetscErrorCode (*function)(MatPartitioning))
188: {
189:   PetscFunctionBegin;
190:   PetscCall(MatInitializePackage());
191:   PetscCall(PetscFunctionListAdd(&MatPartitioningList, sname, function));
192:   PetscFunctionReturn(PETSC_SUCCESS);
193: }

195: /*@C
196:   MatMeshToCellGraphRegister - Registers a mesh-to-cell-graph conversion routine.

198:   Not Collective, No Fortran Support

200:   Input Parameters:
201: + sname    - name of the converter (for example `MATMESHTOCELLGRAPHMETIS` or `MATMESHTOCELLGRAPHPARMETIS`)
202: - function - function pointer that performs the conversion

204:   Level: developer

206:   Example Usage:
207: .vb
208:    MatMeshToCellGraphRegister("metis", MatMeshToCellGraph_Metis);
209: .ve

211:   Then, the converter can be selected at runtime via the option `-mat_mesh_to_cell_graph_type metis`

213: .seealso: [](ch_matrices), `Mat`, `MatMeshToCellGraph()`, `MatMeshToCellGraphType`, `MatMeshToCellGraphRegisterAll()`
214: @*/
215: PetscErrorCode MatMeshToCellGraphRegister(const char sname[], PetscErrorCode (*function)(Mat, PetscInt, Mat *))
216: {
217:   PetscFunctionBegin;
218:   PetscCall(MatInitializePackage());
219:   PetscCall(PetscFunctionListAdd(&MatMeshToCellGraphList, sname, function));
220:   PetscFunctionReturn(PETSC_SUCCESS);
221: }

223: /*@
224:   MatMeshToCellGraph - Convert a mesh to a cell graph.

226:   Collective

228:   Input Parameters:
229: + mesh         - the graph that represents the coupling of the vertices of the mesh
230: - ncommonnodes - mesh elements that share this number of common nodes are considered neighbors, use 2 for triangles and
231:                  quadrilaterials, 3 for tetrahedrals and 4 for hexahedrals

233:   Output Parameter:
234: . dual - the dual graph

236:   Options Database Key:
237: . -mat_mesh_to_cell_graph_type (parmetis|metis) - the conversion package to use; default is ParMETIS if available, otherwise METIS

239:   Level: advanced

241:   Notes:
242:   Converts a `Mat` that represents coupling of vertices of a mesh to a `Mat` that represents the graph of the coupling
243:   between cells (the "dual" graph) and is suitable for partitioning with the `MatPartitioning` object. Use this to
244:   partition cells of a mesh.

246:   Each row of the mesh object represents a single cell in the mesh. For triangles it has 3 entries, quadrilaterials 4 entries,
247:   tetrahedrals 4 entries and hexahedrals 8 entries. You can mix triangles and quadrilaterals in the same mesh, but cannot
248:   mix tetrahedrals and hexahedrals.
249:   The columns of each row of the `Mat` mesh are the global vertex numbers of the vertices of that row's cell.
250:   The number of rows in mesh is number of cells, the number of columns is the number of vertices.

252: .seealso: `MatCreateMPIAdj()`, `MatPartitioningCreate()`, `MatMeshToCellGraphRegister()`
253: @*/
254: PetscErrorCode MatMeshToCellGraph(Mat mesh, PetscInt ncommonnodes, Mat *dual)
255: {
256:   char      type[256];
257:   PetscBool found;
258:   PetscErrorCode (*fn)(Mat, PetscInt, Mat *);
259:   MatMeshToCellGraphType def = NULL;

261:   PetscFunctionBegin;
262:   PetscCall(MatInitializePackage());
263:   if (PetscDefined(HAVE_PARMETIS)) def = MATMESHTOCELLGRAPHPARMETIS;
264:   else if (PetscDefined(HAVE_METIS)) def = MATMESHTOCELLGRAPHMETIS;
265:   PetscCall(PetscOptionsGetString(NULL, NULL, "-mat_mesh_to_cell_graph_type", type, sizeof(type), &found));
266:   if (!found) {
267:     PetscCheck(def, PetscObjectComm((PetscObject)mesh), PETSC_ERR_SUP, "No MatMeshToCellGraph implementations registered. Configure with METIS or ParMETIS");
268:     PetscCall(PetscStrncpy(type, def, sizeof(type)));
269:   }
270:   PetscCall(PetscFunctionListFind(MatMeshToCellGraphList, type, &fn));
271:   PetscCheck(fn, PetscObjectComm((PetscObject)mesh), PETSC_ERR_SUP, "MatMeshToCellGraph type \"%s\" is not available. Configure PETSc with the appropriate package (e.g., --download-metis or --download-parmetis)", type);
272:   PetscCall((*fn)(mesh, ncommonnodes, dual));
273:   PetscFunctionReturn(PETSC_SUCCESS);
274: }

276: /*@
277:   MatPartitioningGetType - Gets the Partitioning method type and name (as a string)
278:   from the partitioning context.

280:   Not Collective

282:   Input Parameter:
283: . partitioning - the partitioning context

285:   Output Parameter:
286: . type - partitioner type

288:   Level: intermediate

290: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningCreate()`, `MatPartitioningRegisterDestroy()`, `MatPartitioningRegisterAll()`
291: @*/
292: PetscErrorCode MatPartitioningGetType(MatPartitioning partitioning, MatPartitioningType *type)
293: {
294:   PetscFunctionBegin;
296:   PetscAssertPointer(type, 2);
297:   *type = ((PetscObject)partitioning)->type_name;
298:   PetscFunctionReturn(PETSC_SUCCESS);
299: }

301: /*@
302:   MatPartitioningSetNParts - Set how many partitions need to be created;
303:   by default this is one per processor. Certain partitioning schemes may
304:   in fact only support that option.

306:   Collective

308:   Input Parameters:
309: + part - the partitioning context
310: - n    - the number of partitions

312:   Level: intermediate

314: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningApply()`
315: @*/
316: PetscErrorCode MatPartitioningSetNParts(MatPartitioning part, PetscInt n)
317: {
318:   PetscFunctionBegin;
319:   part->n = n;
320:   PetscFunctionReturn(PETSC_SUCCESS);
321: }

323: /*@
324:   MatPartitioningApplyND - Gets a nested dissection partitioning for a matrix.

326:   Collective

328:   Input Parameter:
329: . matp - the matrix partitioning object

331:   Output Parameter:
332: . partitioning - the partitioning. For each local node, a positive value indicates the processor
333:                    number the node has been assigned to. Negative x values indicate the separator level -(x+1).

335:   Level: intermediate

337:   Note:
338:   The user can define additional partitionings; see `MatPartitioningRegister()`.

340: .seealso: [](ch_matrices), `Mat`, `MatPartitioningRegister()`, `MatPartitioningCreate()`,
341:           `MatPartitioningDestroy()`, `MatPartitioningSetAdjacency()`, `ISPartitioningToNumbering()`,
342:           `ISPartitioningCount()`
343: @*/
344: PetscErrorCode MatPartitioningApplyND(MatPartitioning matp, IS *partitioning)
345: {
346:   PetscFunctionBegin;
348:   PetscAssertPointer(partitioning, 2);
349:   PetscCheck(matp->adj->assembled, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
350:   PetscCheck(!matp->adj->factortype, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
351:   PetscCall(PetscLogEventBegin(MAT_PartitioningND, matp, 0, 0, 0));
352:   PetscUseTypeMethod(matp, applynd, partitioning);
353:   PetscCall(PetscLogEventEnd(MAT_PartitioningND, matp, 0, 0, 0));

355:   PetscCall(MatPartitioningViewFromOptions(matp, NULL, "-mat_partitioning_view"));
356:   PetscCall(ISViewFromOptions(*partitioning, NULL, "-mat_partitioning_view"));
357:   PetscFunctionReturn(PETSC_SUCCESS);
358: }

360: /*@
361:   MatPartitioningApply - Gets a partitioning for the graph represented by a sparse matrix.

363:   Collective

365:   Input Parameter:
366: . matp - the matrix partitioning object

368:   Output Parameter:
369: . partitioning - the partitioning. For each local node this tells the MPI rank that that node is assigned to.

371:   Options Database Keys:
372: + -mat_partitioning_type type - set the partitioning package or algorithm to use
373: - -mat_partitioning_view      - display information about the partitioning object

375:   Level: beginner

377:    The user can define additional partitionings; see `MatPartitioningRegister()`.

379: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningRegister()`, `MatPartitioningCreate()`,
380:           `MatPartitioningDestroy()`, `MatPartitioningSetAdjacency()`, `ISPartitioningToNumbering()`,
381:           `ISPartitioningCount()`
382: @*/
383: PetscErrorCode MatPartitioningApply(MatPartitioning matp, IS *partitioning)
384: {
385:   PetscBool viewbalance, improve;

387:   PetscFunctionBegin;
389:   PetscAssertPointer(partitioning, 2);
390:   PetscCheck(matp->adj->assembled, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
391:   PetscCheck(!matp->adj->factortype, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
392:   PetscCall(PetscLogEventBegin(MAT_Partitioning, matp, 0, 0, 0));
393:   PetscUseTypeMethod(matp, apply, partitioning);
394:   PetscCall(PetscLogEventEnd(MAT_Partitioning, matp, 0, 0, 0));

396:   PetscCall(MatPartitioningViewFromOptions(matp, NULL, "-mat_partitioning_view"));
397:   PetscCall(ISViewFromOptions(*partitioning, NULL, "-mat_partitioning_view"));

399:   PetscObjectOptionsBegin((PetscObject)matp);
400:   viewbalance = PETSC_FALSE;
401:   PetscCall(PetscOptionsBool("-mat_partitioning_view_imbalance", "Display imbalance information of a partition", NULL, PETSC_FALSE, &viewbalance, NULL));
402:   improve = PETSC_FALSE;
403:   PetscCall(PetscOptionsBool("-mat_partitioning_improve", "Improve the quality of a partition", NULL, PETSC_FALSE, &improve, NULL));
404:   PetscOptionsEnd();

406:   if (improve) PetscCall(MatPartitioningImprove(matp, partitioning));

408:   if (viewbalance) PetscCall(MatPartitioningViewImbalance(matp, *partitioning));
409:   PetscFunctionReturn(PETSC_SUCCESS);
410: }

412: /*@
413:   MatPartitioningImprove - Improves the quality of a given partition.

415:   Collective

417:   Input Parameters:
418: + matp         - the matrix partitioning object
419: - partitioning - the original partitioning. For each local node this tells the processor
420:                    number that that node is assigned to.

422:   Options Database Key:
423: . -mat_partitioning_improve - improve the quality of the given partition

425:   Level: beginner

427: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningApply()`, `MatPartitioningCreate()`,
428:           `MatPartitioningDestroy()`, `MatPartitioningSetAdjacency()`, `ISPartitioningToNumbering()`,
429:           `ISPartitioningCount()`
430: @*/
431: PetscErrorCode MatPartitioningImprove(MatPartitioning matp, IS *partitioning)
432: {
433:   PetscFunctionBegin;
435:   PetscAssertPointer(partitioning, 2);
436:   PetscCheck(matp->adj->assembled, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
437:   PetscCheck(!matp->adj->factortype, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
438:   PetscCall(PetscLogEventBegin(MAT_Partitioning, matp, 0, 0, 0));
439:   PetscTryTypeMethod(matp, improve, partitioning);
440:   PetscCall(PetscLogEventEnd(MAT_Partitioning, matp, 0, 0, 0));
441:   PetscFunctionReturn(PETSC_SUCCESS);
442: }

444: /*@
445:   MatPartitioningViewImbalance - Display partitioning imbalance information.

447:   Collective

449:   Input Parameters:
450: + matp         - the matrix partitioning object
451: - partitioning - the partitioning. For each local node this tells the MPI rank that that node is assigned to.

453:   Options Database Key:
454: . -mat_partitioning_view_balance - view the balance information from the last partitioning

456:   Level: beginner

458: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningApply()`, `MatPartitioningView()`
459: @*/
460: PetscErrorCode MatPartitioningViewImbalance(MatPartitioning matp, IS partitioning)
461: {
462:   PetscMPIInt     nparts;
463:   PetscInt       *subdomainsizes, nlocal, maxsub, minsub, avgsub;
464:   const PetscInt *indices;
465:   PetscViewer     viewer;

467:   PetscFunctionBegin;
470:   PetscCall(PetscMPIIntCast(matp->n, &nparts));
471:   PetscCall(PetscCalloc1(nparts, &subdomainsizes));
472:   PetscCall(ISGetLocalSize(partitioning, &nlocal));
473:   PetscCall(ISGetIndices(partitioning, &indices));
474:   for (PetscInt i = 0; i < nlocal; i++) subdomainsizes[indices[i]] += matp->vertex_weights ? matp->vertex_weights[i] : 1;
475:   PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, subdomainsizes, nparts, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)matp)));
476:   PetscCall(ISRestoreIndices(partitioning, &indices));
477:   minsub = PETSC_INT_MAX, maxsub = PETSC_INT_MIN, avgsub = 0;
478:   for (PetscMPIInt i = 0; i < nparts; i++) {
479:     minsub = PetscMin(minsub, subdomainsizes[i]);
480:     maxsub = PetscMax(maxsub, subdomainsizes[i]);
481:     avgsub += subdomainsizes[i];
482:   }
483:   avgsub /= nparts;
484:   PetscCall(PetscFree(subdomainsizes));
485:   PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)matp), &viewer));
486:   PetscCall(MatPartitioningView(matp, viewer));
487:   PetscCall(PetscViewerASCIIPrintf(viewer, "Partitioning Imbalance Info: Max %" PetscInt_FMT ", Min %" PetscInt_FMT ", Avg %" PetscInt_FMT ", R %g\n", maxsub, minsub, avgsub, (double)(maxsub / (PetscReal)minsub)));
488:   PetscFunctionReturn(PETSC_SUCCESS);
489: }

491: /*@
492:   MatPartitioningSetAdjacency - Sets the adjacency graph (matrix) of the thing to be
493:   partitioned.

495:   Collective

497:   Input Parameters:
498: + part - the partitioning context
499: - adj  - the adjacency matrix, this can be any `MatType` but the natural representation is `MATMPIADJ`

501:   Level: beginner

503: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningCreate()`
504: @*/
505: PetscErrorCode MatPartitioningSetAdjacency(MatPartitioning part, Mat adj)
506: {
507:   PetscFunctionBegin;
510:   part->adj = adj;
511:   PetscFunctionReturn(PETSC_SUCCESS);
512: }

514: /*@
515:   MatPartitioningDestroy - Destroys the partitioning context.

517:   Collective

519:   Input Parameter:
520: . part - the partitioning context

522:   Level: beginner

524: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningCreate()`
525: @*/
526: PetscErrorCode MatPartitioningDestroy(MatPartitioning *part)
527: {
528:   PetscFunctionBegin;
529:   if (!*part) PetscFunctionReturn(PETSC_SUCCESS);
531:   if (--((PetscObject)*part)->refct > 0) {
532:     *part = NULL;
533:     PetscFunctionReturn(PETSC_SUCCESS);
534:   }

536:   PetscTryTypeMethod(*part, destroy);
537:   PetscCall(PetscFree((*part)->vertex_weights));
538:   PetscCall(PetscFree((*part)->part_weights));
539:   PetscCall(PetscHeaderDestroy(part));
540:   PetscFunctionReturn(PETSC_SUCCESS);
541: }

543: /*@C
544:   MatPartitioningSetVertexWeights - Sets the weights for vertices for a partitioning.

546:   Logically Collective

548:   Input Parameters:
549: + part    - the partitioning context
550: - weights - the weights, on each process this array must have the same size as the number of local rows times the value passed with `MatPartitioningSetNumberVertexWeights()` or
551:             1 if that is not provided

553:   Level: beginner

555:   Notes:
556:   The array weights is freed by PETSc so the user should not free the array. In C/C++
557:   the array must be obtained with a call to `PetscMalloc()`, not malloc().

559:   The weights may not be used by some partitioners

561:   Fortran Note:
562:   The array `weights` is copied during this function call.

564: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningSetType()`, `MatPartitioningSetPartitionWeights()`, `MatPartitioningSetNumberVertexWeights()`
565: @*/
566: PetscErrorCode MatPartitioningSetVertexWeights(MatPartitioning part, const PetscInt weights[])
567: {
568:   PetscFunctionBegin;
570:   PetscCall(PetscFree(part->vertex_weights));
571:   part->vertex_weights = (PetscInt *)weights;
572:   PetscFunctionReturn(PETSC_SUCCESS);
573: }

575: /*@C
576:   MatPartitioningSetPartitionWeights - Sets the weights for each partition.

578:   Logically Collective

580:   Input Parameters:
581: + part    - the partitioning context
582: - weights - An array of size nparts that is used to specify the fraction of
583:             vertex weight that should be distributed to each sub-domain for
584:             the balance constraint. If all of the sub-domains are to be of
585:             the same size, then each of the nparts elements should be set
586:             to a value of 1/nparts. Note that the sum of all of the weights
587:             should be one.

589:   Level: beginner

591:   Note:
592:   The array weights is freed by PETSc so the user should not free the array. In C/C++
593:   the array must be obtained with a call to `PetscMalloc()`, not malloc().

595:   Fortran Note:
596:   The array `weights` is copied during this function call.

598: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningSetVertexWeights()`, `MatPartitioningCreate()`, `MatPartitioningSetType()`
599: @*/
600: PetscErrorCode MatPartitioningSetPartitionWeights(MatPartitioning part, const PetscReal weights[])
601: {
602:   PetscFunctionBegin;
604:   PetscCall(PetscFree(part->part_weights));
605:   part->part_weights = (PetscReal *)weights;
606:   PetscFunctionReturn(PETSC_SUCCESS);
607: }

609: /*@
610:   MatPartitioningSetUseEdgeWeights - Set a flag to indicate whether or not to use edge weights.

612:   Logically Collective

614:   Input Parameters:
615: + part             - the partitioning context
616: - use_edge_weights - the flag indicateing whether or not to use edge weights. By default no edge weights will be used,
617:                      that is, use_edge_weights is set to FALSE. If set use_edge_weights to TRUE, users need to make sure legal
618:                      edge weights are stored in an ADJ matrix.

620:   Options Database Key:
621: . -mat_partitioning_use_edge_weights - (true or false)

623:   Level: beginner

625: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningSetType()`, `MatPartitioningSetVertexWeights()`, `MatPartitioningSetPartitionWeights()`
626: @*/
627: PetscErrorCode MatPartitioningSetUseEdgeWeights(MatPartitioning part, PetscBool use_edge_weights)
628: {
629:   PetscFunctionBegin;
631:   part->use_edge_weights = use_edge_weights;
632:   PetscFunctionReturn(PETSC_SUCCESS);
633: }

635: /*@
636:   MatPartitioningGetUseEdgeWeights - Get a flag that indicates whether or not to edge weights are used.

638:   Logically Collective

640:   Input Parameter:
641: . part - the partitioning context

643:   Output Parameter:
644: . use_edge_weights - the flag indicateing whether or not to edge weights are used.

646:   Level: beginner

648: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningSetType()`, `MatPartitioningSetVertexWeights()`, `MatPartitioningSetPartitionWeights()`,
649:           `MatPartitioningSetUseEdgeWeights`
650: @*/
651: PetscErrorCode MatPartitioningGetUseEdgeWeights(MatPartitioning part, PetscBool *use_edge_weights)
652: {
653:   PetscFunctionBegin;
655:   PetscAssertPointer(use_edge_weights, 2);
656:   *use_edge_weights = part->use_edge_weights;
657:   PetscFunctionReturn(PETSC_SUCCESS);
658: }

660: /*@
661:   MatPartitioningCreate - Creates a partitioning context.

663:   Collective

665:   Input Parameter:
666: . comm - MPI communicator

668:   Output Parameter:
669: . newp - location to put the context

671:   Level: beginner

673: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningSetType()`, `MatPartitioningApply()`, `MatPartitioningDestroy()`,
674:           `MatPartitioningSetAdjacency()`
675: @*/
676: PetscErrorCode MatPartitioningCreate(MPI_Comm comm, MatPartitioning *newp)
677: {
678:   MatPartitioning part;
679:   PetscMPIInt     size;

681:   PetscFunctionBegin;
682:   PetscAssertPointer(newp, 2);
683:   PetscCall(MatInitializePackage());

685:   PetscCall(PetscHeaderCreate(part, MAT_PARTITIONING_CLASSID, "MatPartitioning", "Matrix/graph partitioning", "MatGraphOperations", comm, MatPartitioningDestroy, MatPartitioningView));
686:   part->vertex_weights   = NULL;
687:   part->part_weights     = NULL;
688:   part->use_edge_weights = PETSC_FALSE; /* By default we don't use edge weights */

690:   PetscCallMPI(MPI_Comm_size(comm, &size));
691:   part->n    = size;
692:   part->ncon = 1;

694:   *newp = part;
695:   PetscFunctionReturn(PETSC_SUCCESS);
696: }

698: /*@
699:   MatPartitioningViewFromOptions - View a partitioning context from the options database

701:   Collective

703:   Input Parameters:
704: + A    - the partitioning context
705: . obj  - Optional object that provides the prefix used in the options database check
706: - name - command line option

708:   Options Database Key:
709: . -name [viewertype][:...] - option name and values. See `PetscObjectViewFromOptions()` for the possible arguments

711:   Level: intermediate

713: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningView()`, `PetscObjectViewFromOptions()`, `MatPartitioningCreate()`
714: @*/
715: PetscErrorCode MatPartitioningViewFromOptions(MatPartitioning A, PetscObject obj, const char name[])
716: {
717:   PetscFunctionBegin;
719:   PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
720:   PetscFunctionReturn(PETSC_SUCCESS);
721: }

723: /*@
724:   MatPartitioningView - Prints the partitioning data structure.

726:   Collective

728:   Input Parameters:
729: + part   - the partitioning context
730: - viewer - optional visualization context

732:   Level: intermediate

734:   Note:
735:   The available visualization contexts include
736: +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
737: -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
738:   output where only the first processor opens
739:   the file.  All other processors send their
740:   data to the first processor to print.

742:   The user can open alternative visualization contexts with
743: .     `PetscViewerASCIIOpen()` - output to a specified file

745: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `PetscViewer`, `PetscViewerASCIIOpen()`
746: @*/
747: PetscErrorCode MatPartitioningView(MatPartitioning part, PetscViewer viewer)
748: {
749:   PetscBool isascii;

751:   PetscFunctionBegin;
753:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)part), &viewer));
755:   PetscCheckSameComm(part, 1, viewer, 2);

757:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
758:   if (isascii) {
759:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)part, viewer));
760:     if (part->vertex_weights) PetscCall(PetscViewerASCIIPrintf(viewer, "  Using vertex weights\n"));
761:   }
762:   PetscCall(PetscViewerASCIIPushTab(viewer));
763:   PetscTryTypeMethod(part, view, viewer);
764:   PetscCall(PetscViewerASCIIPopTab(viewer));
765:   PetscFunctionReturn(PETSC_SUCCESS);
766: }

768: /*@
769:   MatPartitioningSetType - Sets the type of partitioner to use

771:   Collective

773:   Input Parameters:
774: + part - the partitioning context.
775: - type - a known method

777:   Options Database Key:
778: . -mat_partitioning_type type - (for instance, parmetis), see `MatPartitioningType`

780:   Level: intermediate

782: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningApply()`, `MatPartitioningType`
783: @*/
784: PetscErrorCode MatPartitioningSetType(MatPartitioning part, MatPartitioningType type)
785: {
786:   PetscBool match;
787:   PetscErrorCode (*r)(MatPartitioning);

789:   PetscFunctionBegin;
791:   PetscAssertPointer(type, 2);

793:   PetscCall(PetscObjectTypeCompare((PetscObject)part, type, &match));
794:   if (match) PetscFunctionReturn(PETSC_SUCCESS);

796:   PetscTryTypeMethod(part, destroy);
797:   part->ops->destroy = NULL;

799:   part->data = NULL;
800:   PetscCall(PetscMemzero(part->ops, sizeof(struct _MatPartitioningOps)));

802:   PetscCall(PetscFunctionListFind(MatPartitioningList, type, &r));
803:   PetscCheck(r, PetscObjectComm((PetscObject)part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown partitioning type %s", type);

805:   PetscCall((*r)(part));

807:   PetscCall(PetscFree(((PetscObject)part)->type_name));
808:   PetscCall(PetscStrallocpy(type, &((PetscObject)part)->type_name));
809:   PetscFunctionReturn(PETSC_SUCCESS);
810: }

812: /*@
813:   MatPartitioningSetFromOptions - Sets various partitioning options from the
814:   options database for the partitioning object

816:   Collective

818:   Input Parameter:
819: . part - the partitioning context.

821:   Options Database Keys:
822: + -mat_partitioning_type type - (for instance, parmetis), use -help for a list of available methods
823: - -mat_partitioning_nparts    - number of subgraphs

825:   Level: beginner

827:   Note:
828:   If the partitioner has not been set by the user it uses one of the installed partitioner such as ParMetis. If there are
829:   no installed partitioners it does no repartioning.

831: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`
832: @*/
833: PetscErrorCode MatPartitioningSetFromOptions(MatPartitioning part)
834: {
835:   PetscBool   flag;
836:   char        type[256];
837:   const char *def;

839:   PetscFunctionBegin;
840:   PetscObjectOptionsBegin((PetscObject)part);
841:   if (!((PetscObject)part)->type_name) {
842: #if PetscDefined(HAVE_PARMETIS)
843:     def = MATPARTITIONINGPARMETIS;
844: #elif PetscDefined(HAVE_CHACO)
845:     def = MATPARTITIONINGCHACO;
846: #elif PetscDefined(HAVE_PARTY)
847:     def = MATPARTITIONINGPARTY;
848: #elif PetscDefined(HAVE_PTSCOTCH)
849:     def = MATPARTITIONINGPTSCOTCH;
850: #else
851:     def = MATPARTITIONINGCURRENT;
852: #endif
853:   } else {
854:     def = ((PetscObject)part)->type_name;
855:   }
856:   PetscCall(PetscOptionsFList("-mat_partitioning_type", "Type of partitioner", "MatPartitioningSetType", MatPartitioningList, def, type, 256, &flag));
857:   if (flag) PetscCall(MatPartitioningSetType(part, type));

859:   PetscCall(PetscOptionsInt("-mat_partitioning_nparts", "number of fine parts", NULL, part->n, &part->n, &flag));

861:   PetscCall(PetscOptionsBool("-mat_partitioning_use_edge_weights", "whether or not to use edge weights", NULL, part->use_edge_weights, &part->use_edge_weights, &flag));

863:   /*
864:     Set the type if it was never set.
865:   */
866:   if (!((PetscObject)part)->type_name) PetscCall(MatPartitioningSetType(part, def));

868:   PetscTryTypeMethod(part, setfromoptions, PetscOptionsObject);
869:   PetscOptionsEnd();
870:   PetscFunctionReturn(PETSC_SUCCESS);
871: }

873: /*@
874:   MatPartitioningSetNumberVertexWeights - Sets the number of weights per vertex

876:   Not Collective

878:   Input Parameters:
879: + partitioning - the partitioning context
880: - ncon         - the number of weights

882:   Level: intermediate

884: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningSetVertexWeights()`
885: @*/
886: PetscErrorCode MatPartitioningSetNumberVertexWeights(MatPartitioning partitioning, PetscInt ncon)
887: {
888:   PetscFunctionBegin;
890:   partitioning->ncon = ncon;
891:   PetscFunctionReturn(PETSC_SUCCESS);
892: }