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: }