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;
261: PetscFunctionBegin;
262: PetscCall(MatInitializePackage());
263: #if defined(PETSC_HAVE_PARMETIS)
264: def = MATMESHTOCELLGRAPHPARMETIS;
265: #elif defined(PETSC_HAVE_METIS)
266: def = MATMESHTOCELLGRAPHMETIS;
267: #else
268: def = NULL;
269: #endif
270: PetscCall(PetscOptionsGetString(NULL, NULL, "-mat_mesh_to_cell_graph_type", type, sizeof(type), &found));
271: if (!found) {
272: PetscCheck(def, PetscObjectComm((PetscObject)mesh), PETSC_ERR_SUP, "No MatMeshToCellGraph implementations registered. Configure with METIS or ParMETIS");
273: PetscCall(PetscStrncpy(type, def, sizeof(type)));
274: }
275: PetscCall(PetscFunctionListFind(MatMeshToCellGraphList, type, &fn));
276: 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);
277: PetscCall((*fn)(mesh, ncommonnodes, dual));
278: PetscFunctionReturn(PETSC_SUCCESS);
279: }
281: /*@
282: MatPartitioningGetType - Gets the Partitioning method type and name (as a string)
283: from the partitioning context.
285: Not Collective
287: Input Parameter:
288: . partitioning - the partitioning context
290: Output Parameter:
291: . type - partitioner type
293: Level: intermediate
295: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningCreate()`, `MatPartitioningRegisterDestroy()`, `MatPartitioningRegisterAll()`
296: @*/
297: PetscErrorCode MatPartitioningGetType(MatPartitioning partitioning, MatPartitioningType *type)
298: {
299: PetscFunctionBegin;
301: PetscAssertPointer(type, 2);
302: *type = ((PetscObject)partitioning)->type_name;
303: PetscFunctionReturn(PETSC_SUCCESS);
304: }
306: /*@
307: MatPartitioningSetNParts - Set how many partitions need to be created;
308: by default this is one per processor. Certain partitioning schemes may
309: in fact only support that option.
311: Collective
313: Input Parameters:
314: + part - the partitioning context
315: - n - the number of partitions
317: Level: intermediate
319: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningApply()`
320: @*/
321: PetscErrorCode MatPartitioningSetNParts(MatPartitioning part, PetscInt n)
322: {
323: PetscFunctionBegin;
324: part->n = n;
325: PetscFunctionReturn(PETSC_SUCCESS);
326: }
328: /*@
329: MatPartitioningApplyND - Gets a nested dissection partitioning for a matrix.
331: Collective
333: Input Parameter:
334: . matp - the matrix partitioning object
336: Output Parameter:
337: . partitioning - the partitioning. For each local node, a positive value indicates the processor
338: number the node has been assigned to. Negative x values indicate the separator level -(x+1).
340: Level: intermediate
342: Note:
343: The user can define additional partitionings; see `MatPartitioningRegister()`.
345: .seealso: [](ch_matrices), `Mat`, `MatPartitioningRegister()`, `MatPartitioningCreate()`,
346: `MatPartitioningDestroy()`, `MatPartitioningSetAdjacency()`, `ISPartitioningToNumbering()`,
347: `ISPartitioningCount()`
348: @*/
349: PetscErrorCode MatPartitioningApplyND(MatPartitioning matp, IS *partitioning)
350: {
351: PetscFunctionBegin;
353: PetscAssertPointer(partitioning, 2);
354: PetscCheck(matp->adj->assembled, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
355: PetscCheck(!matp->adj->factortype, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
356: PetscCall(PetscLogEventBegin(MAT_PartitioningND, matp, 0, 0, 0));
357: PetscUseTypeMethod(matp, applynd, partitioning);
358: PetscCall(PetscLogEventEnd(MAT_PartitioningND, matp, 0, 0, 0));
360: PetscCall(MatPartitioningViewFromOptions(matp, NULL, "-mat_partitioning_view"));
361: PetscCall(ISViewFromOptions(*partitioning, NULL, "-mat_partitioning_view"));
362: PetscFunctionReturn(PETSC_SUCCESS);
363: }
365: /*@
366: MatPartitioningApply - Gets a partitioning for the graph represented by a sparse matrix.
368: Collective
370: Input Parameter:
371: . matp - the matrix partitioning object
373: Output Parameter:
374: . partitioning - the partitioning. For each local node this tells the MPI rank that that node is assigned to.
376: Options Database Keys:
377: + -mat_partitioning_type type - set the partitioning package or algorithm to use
378: - -mat_partitioning_view - display information about the partitioning object
380: Level: beginner
382: The user can define additional partitionings; see `MatPartitioningRegister()`.
384: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningRegister()`, `MatPartitioningCreate()`,
385: `MatPartitioningDestroy()`, `MatPartitioningSetAdjacency()`, `ISPartitioningToNumbering()`,
386: `ISPartitioningCount()`
387: @*/
388: PetscErrorCode MatPartitioningApply(MatPartitioning matp, IS *partitioning)
389: {
390: PetscBool viewbalance, improve;
392: PetscFunctionBegin;
394: PetscAssertPointer(partitioning, 2);
395: PetscCheck(matp->adj->assembled, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
396: PetscCheck(!matp->adj->factortype, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
397: PetscCall(PetscLogEventBegin(MAT_Partitioning, matp, 0, 0, 0));
398: PetscUseTypeMethod(matp, apply, partitioning);
399: PetscCall(PetscLogEventEnd(MAT_Partitioning, matp, 0, 0, 0));
401: PetscCall(MatPartitioningViewFromOptions(matp, NULL, "-mat_partitioning_view"));
402: PetscCall(ISViewFromOptions(*partitioning, NULL, "-mat_partitioning_view"));
404: PetscObjectOptionsBegin((PetscObject)matp);
405: viewbalance = PETSC_FALSE;
406: PetscCall(PetscOptionsBool("-mat_partitioning_view_imbalance", "Display imbalance information of a partition", NULL, PETSC_FALSE, &viewbalance, NULL));
407: improve = PETSC_FALSE;
408: PetscCall(PetscOptionsBool("-mat_partitioning_improve", "Improve the quality of a partition", NULL, PETSC_FALSE, &improve, NULL));
409: PetscOptionsEnd();
411: if (improve) PetscCall(MatPartitioningImprove(matp, partitioning));
413: if (viewbalance) PetscCall(MatPartitioningViewImbalance(matp, *partitioning));
414: PetscFunctionReturn(PETSC_SUCCESS);
415: }
417: /*@
418: MatPartitioningImprove - Improves the quality of a given partition.
420: Collective
422: Input Parameters:
423: + matp - the matrix partitioning object
424: - partitioning - the original partitioning. For each local node this tells the processor
425: number that that node is assigned to.
427: Options Database Key:
428: . -mat_partitioning_improve - improve the quality of the given partition
430: Level: beginner
432: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningApply()`, `MatPartitioningCreate()`,
433: `MatPartitioningDestroy()`, `MatPartitioningSetAdjacency()`, `ISPartitioningToNumbering()`,
434: `ISPartitioningCount()`
435: @*/
436: PetscErrorCode MatPartitioningImprove(MatPartitioning matp, IS *partitioning)
437: {
438: PetscFunctionBegin;
440: PetscAssertPointer(partitioning, 2);
441: PetscCheck(matp->adj->assembled, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for unassembled matrix");
442: PetscCheck(!matp->adj->factortype, PetscObjectComm((PetscObject)matp), PETSC_ERR_ARG_WRONGSTATE, "Not for factored matrix");
443: PetscCall(PetscLogEventBegin(MAT_Partitioning, matp, 0, 0, 0));
444: PetscTryTypeMethod(matp, improve, partitioning);
445: PetscCall(PetscLogEventEnd(MAT_Partitioning, matp, 0, 0, 0));
446: PetscFunctionReturn(PETSC_SUCCESS);
447: }
449: /*@
450: MatPartitioningViewImbalance - Display partitioning imbalance information.
452: Collective
454: Input Parameters:
455: + matp - the matrix partitioning object
456: - partitioning - the partitioning. For each local node this tells the MPI rank that that node is assigned to.
458: Options Database Key:
459: . -mat_partitioning_view_balance - view the balance information from the last partitioning
461: Level: beginner
463: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningApply()`, `MatPartitioningView()`
464: @*/
465: PetscErrorCode MatPartitioningViewImbalance(MatPartitioning matp, IS partitioning)
466: {
467: PetscMPIInt nparts;
468: PetscInt *subdomainsizes, *subdomainsizes_tmp, nlocal, maxsub, minsub, avgsub;
469: const PetscInt *indices;
470: PetscViewer viewer;
472: PetscFunctionBegin;
475: PetscCall(PetscMPIIntCast(matp->n, &nparts));
476: PetscCall(PetscCalloc2(nparts, &subdomainsizes, nparts, &subdomainsizes_tmp));
477: PetscCall(ISGetLocalSize(partitioning, &nlocal));
478: PetscCall(ISGetIndices(partitioning, &indices));
479: for (PetscInt i = 0; i < nlocal; i++) subdomainsizes_tmp[indices[i]] += matp->vertex_weights ? matp->vertex_weights[i] : 1;
480: PetscCallMPI(MPIU_Allreduce(subdomainsizes_tmp, subdomainsizes, nparts, MPIU_INT, MPI_SUM, PetscObjectComm((PetscObject)matp)));
481: PetscCall(ISRestoreIndices(partitioning, &indices));
482: minsub = PETSC_INT_MAX, maxsub = PETSC_INT_MIN, avgsub = 0;
483: for (PetscMPIInt i = 0; i < nparts; i++) {
484: minsub = PetscMin(minsub, subdomainsizes[i]);
485: maxsub = PetscMax(maxsub, subdomainsizes[i]);
486: avgsub += subdomainsizes[i];
487: }
488: avgsub /= nparts;
489: PetscCall(PetscFree2(subdomainsizes, subdomainsizes_tmp));
490: PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)matp), &viewer));
491: PetscCall(MatPartitioningView(matp, viewer));
492: 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)));
493: PetscFunctionReturn(PETSC_SUCCESS);
494: }
496: /*@
497: MatPartitioningSetAdjacency - Sets the adjacency graph (matrix) of the thing to be
498: partitioned.
500: Collective
502: Input Parameters:
503: + part - the partitioning context
504: - adj - the adjacency matrix, this can be any `MatType` but the natural representation is `MATMPIADJ`
506: Level: beginner
508: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningCreate()`
509: @*/
510: PetscErrorCode MatPartitioningSetAdjacency(MatPartitioning part, Mat adj)
511: {
512: PetscFunctionBegin;
515: part->adj = adj;
516: PetscFunctionReturn(PETSC_SUCCESS);
517: }
519: /*@
520: MatPartitioningDestroy - Destroys the partitioning context.
522: Collective
524: Input Parameter:
525: . part - the partitioning context
527: Level: beginner
529: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningType`, `MatPartitioningCreate()`
530: @*/
531: PetscErrorCode MatPartitioningDestroy(MatPartitioning *part)
532: {
533: PetscFunctionBegin;
534: if (!*part) PetscFunctionReturn(PETSC_SUCCESS);
536: if (--((PetscObject)*part)->refct > 0) {
537: *part = NULL;
538: PetscFunctionReturn(PETSC_SUCCESS);
539: }
541: PetscTryTypeMethod(*part, destroy);
542: PetscCall(PetscFree((*part)->vertex_weights));
543: PetscCall(PetscFree((*part)->part_weights));
544: PetscCall(PetscHeaderDestroy(part));
545: PetscFunctionReturn(PETSC_SUCCESS);
546: }
548: /*@C
549: MatPartitioningSetVertexWeights - Sets the weights for vertices for a partitioning.
551: Logically Collective
553: Input Parameters:
554: + part - the partitioning context
555: - 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
556: 1 if that is not provided
558: Level: beginner
560: Notes:
561: The array weights is freed by PETSc so the user should not free the array. In C/C++
562: the array must be obtained with a call to `PetscMalloc()`, not malloc().
564: The weights may not be used by some partitioners
566: Fortran Note:
567: The array `weights` is copied during this function call.
569: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningSetType()`, `MatPartitioningSetPartitionWeights()`, `MatPartitioningSetNumberVertexWeights()`
570: @*/
571: PetscErrorCode MatPartitioningSetVertexWeights(MatPartitioning part, const PetscInt weights[])
572: {
573: PetscFunctionBegin;
575: PetscCall(PetscFree(part->vertex_weights));
576: part->vertex_weights = (PetscInt *)weights;
577: PetscFunctionReturn(PETSC_SUCCESS);
578: }
580: /*@C
581: MatPartitioningSetPartitionWeights - Sets the weights for each partition.
583: Logically Collective
585: Input Parameters:
586: + part - the partitioning context
587: - weights - An array of size nparts that is used to specify the fraction of
588: vertex weight that should be distributed to each sub-domain for
589: the balance constraint. If all of the sub-domains are to be of
590: the same size, then each of the nparts elements should be set
591: to a value of 1/nparts. Note that the sum of all of the weights
592: should be one.
594: Level: beginner
596: Note:
597: The array weights is freed by PETSc so the user should not free the array. In C/C++
598: the array must be obtained with a call to `PetscMalloc()`, not malloc().
600: Fortran Note:
601: The array `weights` is copied during this function call.
603: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningSetVertexWeights()`, `MatPartitioningCreate()`, `MatPartitioningSetType()`
604: @*/
605: PetscErrorCode MatPartitioningSetPartitionWeights(MatPartitioning part, const PetscReal weights[])
606: {
607: PetscFunctionBegin;
609: PetscCall(PetscFree(part->part_weights));
610: part->part_weights = (PetscReal *)weights;
611: PetscFunctionReturn(PETSC_SUCCESS);
612: }
614: /*@
615: MatPartitioningSetUseEdgeWeights - Set a flag to indicate whether or not to use edge weights.
617: Logically Collective
619: Input Parameters:
620: + part - the partitioning context
621: - use_edge_weights - the flag indicateing whether or not to use edge weights. By default no edge weights will be used,
622: that is, use_edge_weights is set to FALSE. If set use_edge_weights to TRUE, users need to make sure legal
623: edge weights are stored in an ADJ matrix.
625: Options Database Key:
626: . -mat_partitioning_use_edge_weights - (true or false)
628: Level: beginner
630: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningSetType()`, `MatPartitioningSetVertexWeights()`, `MatPartitioningSetPartitionWeights()`
631: @*/
632: PetscErrorCode MatPartitioningSetUseEdgeWeights(MatPartitioning part, PetscBool use_edge_weights)
633: {
634: PetscFunctionBegin;
636: part->use_edge_weights = use_edge_weights;
637: PetscFunctionReturn(PETSC_SUCCESS);
638: }
640: /*@
641: MatPartitioningGetUseEdgeWeights - Get a flag that indicates whether or not to edge weights are used.
643: Logically Collective
645: Input Parameter:
646: . part - the partitioning context
648: Output Parameter:
649: . use_edge_weights - the flag indicateing whether or not to edge weights are used.
651: Level: beginner
653: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningSetType()`, `MatPartitioningSetVertexWeights()`, `MatPartitioningSetPartitionWeights()`,
654: `MatPartitioningSetUseEdgeWeights`
655: @*/
656: PetscErrorCode MatPartitioningGetUseEdgeWeights(MatPartitioning part, PetscBool *use_edge_weights)
657: {
658: PetscFunctionBegin;
660: PetscAssertPointer(use_edge_weights, 2);
661: *use_edge_weights = part->use_edge_weights;
662: PetscFunctionReturn(PETSC_SUCCESS);
663: }
665: /*@
666: MatPartitioningCreate - Creates a partitioning context.
668: Collective
670: Input Parameter:
671: . comm - MPI communicator
673: Output Parameter:
674: . newp - location to put the context
676: Level: beginner
678: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningSetType()`, `MatPartitioningApply()`, `MatPartitioningDestroy()`,
679: `MatPartitioningSetAdjacency()`
680: @*/
681: PetscErrorCode MatPartitioningCreate(MPI_Comm comm, MatPartitioning *newp)
682: {
683: MatPartitioning part;
684: PetscMPIInt size;
686: PetscFunctionBegin;
687: PetscAssertPointer(newp, 2);
688: PetscCall(MatInitializePackage());
690: PetscCall(PetscHeaderCreate(part, MAT_PARTITIONING_CLASSID, "MatPartitioning", "Matrix/graph partitioning", "MatGraphOperations", comm, MatPartitioningDestroy, MatPartitioningView));
691: part->vertex_weights = NULL;
692: part->part_weights = NULL;
693: part->use_edge_weights = PETSC_FALSE; /* By default we don't use edge weights */
695: PetscCallMPI(MPI_Comm_size(comm, &size));
696: part->n = size;
697: part->ncon = 1;
699: *newp = part;
700: PetscFunctionReturn(PETSC_SUCCESS);
701: }
703: /*@
704: MatPartitioningViewFromOptions - View a partitioning context from the options database
706: Collective
708: Input Parameters:
709: + A - the partitioning context
710: . obj - Optional object that provides the prefix used in the options database check
711: - name - command line option
713: Options Database Key:
714: . -name [viewertype][:...] - option name and values. See `PetscObjectViewFromOptions()` for the possible arguments
716: Level: intermediate
718: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningView()`, `PetscObjectViewFromOptions()`, `MatPartitioningCreate()`
719: @*/
720: PetscErrorCode MatPartitioningViewFromOptions(MatPartitioning A, PetscObject obj, const char name[])
721: {
722: PetscFunctionBegin;
724: PetscCall(PetscObjectViewFromOptions((PetscObject)A, obj, name));
725: PetscFunctionReturn(PETSC_SUCCESS);
726: }
728: /*@
729: MatPartitioningView - Prints the partitioning data structure.
731: Collective
733: Input Parameters:
734: + part - the partitioning context
735: - viewer - optional visualization context
737: Level: intermediate
739: Note:
740: The available visualization contexts include
741: + `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
742: - `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard
743: output where only the first processor opens
744: the file. All other processors send their
745: data to the first processor to print.
747: The user can open alternative visualization contexts with
748: . `PetscViewerASCIIOpen()` - output to a specified file
750: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `PetscViewer`, `PetscViewerASCIIOpen()`
751: @*/
752: PetscErrorCode MatPartitioningView(MatPartitioning part, PetscViewer viewer)
753: {
754: PetscBool isascii;
756: PetscFunctionBegin;
758: if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)part), &viewer));
760: PetscCheckSameComm(part, 1, viewer, 2);
762: PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
763: if (isascii) {
764: PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)part, viewer));
765: if (part->vertex_weights) PetscCall(PetscViewerASCIIPrintf(viewer, " Using vertex weights\n"));
766: }
767: PetscCall(PetscViewerASCIIPushTab(viewer));
768: PetscTryTypeMethod(part, view, viewer);
769: PetscCall(PetscViewerASCIIPopTab(viewer));
770: PetscFunctionReturn(PETSC_SUCCESS);
771: }
773: /*@
774: MatPartitioningSetType - Sets the type of partitioner to use
776: Collective
778: Input Parameters:
779: + part - the partitioning context.
780: - type - a known method
782: Options Database Key:
783: . -mat_partitioning_type type - (for instance, parmetis), see `MatPartitioningType`
785: Level: intermediate
787: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningCreate()`, `MatPartitioningApply()`, `MatPartitioningType`
788: @*/
789: PetscErrorCode MatPartitioningSetType(MatPartitioning part, MatPartitioningType type)
790: {
791: PetscBool match;
792: PetscErrorCode (*r)(MatPartitioning);
794: PetscFunctionBegin;
796: PetscAssertPointer(type, 2);
798: PetscCall(PetscObjectTypeCompare((PetscObject)part, type, &match));
799: if (match) PetscFunctionReturn(PETSC_SUCCESS);
801: PetscTryTypeMethod(part, destroy);
802: part->ops->destroy = NULL;
804: part->data = NULL;
805: PetscCall(PetscMemzero(part->ops, sizeof(struct _MatPartitioningOps)));
807: PetscCall(PetscFunctionListFind(MatPartitioningList, type, &r));
808: PetscCheck(r, PetscObjectComm((PetscObject)part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown partitioning type %s", type);
810: PetscCall((*r)(part));
812: PetscCall(PetscFree(((PetscObject)part)->type_name));
813: PetscCall(PetscStrallocpy(type, &((PetscObject)part)->type_name));
814: PetscFunctionReturn(PETSC_SUCCESS);
815: }
817: /*@
818: MatPartitioningSetFromOptions - Sets various partitioning options from the
819: options database for the partitioning object
821: Collective
823: Input Parameter:
824: . part - the partitioning context.
826: Options Database Keys:
827: + -mat_partitioning_type type - (for instance, parmetis), use -help for a list of available methods
828: - -mat_partitioning_nparts - number of subgraphs
830: Level: beginner
832: Note:
833: If the partitioner has not been set by the user it uses one of the installed partitioner such as ParMetis. If there are
834: no installed partitioners it does no repartioning.
836: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`
837: @*/
838: PetscErrorCode MatPartitioningSetFromOptions(MatPartitioning part)
839: {
840: PetscBool flag;
841: char type[256];
842: const char *def;
844: PetscFunctionBegin;
845: PetscObjectOptionsBegin((PetscObject)part);
846: if (!((PetscObject)part)->type_name) {
847: #if defined(PETSC_HAVE_PARMETIS)
848: def = MATPARTITIONINGPARMETIS;
849: #elif defined(PETSC_HAVE_CHACO)
850: def = MATPARTITIONINGCHACO;
851: #elif defined(PETSC_HAVE_PARTY)
852: def = MATPARTITIONINGPARTY;
853: #elif defined(PETSC_HAVE_PTSCOTCH)
854: def = MATPARTITIONINGPTSCOTCH;
855: #else
856: def = MATPARTITIONINGCURRENT;
857: #endif
858: } else {
859: def = ((PetscObject)part)->type_name;
860: }
861: PetscCall(PetscOptionsFList("-mat_partitioning_type", "Type of partitioner", "MatPartitioningSetType", MatPartitioningList, def, type, 256, &flag));
862: if (flag) PetscCall(MatPartitioningSetType(part, type));
864: PetscCall(PetscOptionsInt("-mat_partitioning_nparts", "number of fine parts", NULL, part->n, &part->n, &flag));
866: PetscCall(PetscOptionsBool("-mat_partitioning_use_edge_weights", "whether or not to use edge weights", NULL, part->use_edge_weights, &part->use_edge_weights, &flag));
868: /*
869: Set the type if it was never set.
870: */
871: if (!((PetscObject)part)->type_name) PetscCall(MatPartitioningSetType(part, def));
873: PetscTryTypeMethod(part, setfromoptions, PetscOptionsObject);
874: PetscOptionsEnd();
875: PetscFunctionReturn(PETSC_SUCCESS);
876: }
878: /*@
879: MatPartitioningSetNumberVertexWeights - Sets the number of weights per vertex
881: Not Collective
883: Input Parameters:
884: + partitioning - the partitioning context
885: - ncon - the number of weights
887: Level: intermediate
889: .seealso: [](ch_matrices), `Mat`, `MatPartitioning`, `MatPartitioningSetVertexWeights()`
890: @*/
891: PetscErrorCode MatPartitioningSetNumberVertexWeights(MatPartitioning partitioning, PetscInt ncon)
892: {
893: PetscFunctionBegin;
895: partitioning->ncon = ncon;
896: PetscFunctionReturn(PETSC_SUCCESS);
897: }