Actual source code: ex323.c
1: static char help[] = "Tests MatPartitioning with PT-SCOTCH when a process owns no graph vertices.\n\n";
3: #include <petscmat.h>
5: int main(int argc, char **args)
6: {
7: Mat adj;
8: MatPartitioning part;
9: IS is;
10: PetscInt N, npath, start, n, nlocal, nz, v, i;
11: PetscInt *xadj, *adjncy, *vweights = NULL, *eweights = NULL;
12: PetscMPIInt rank, size;
13: PetscBool use_vertex_weights = PETSC_FALSE, use_edge_weights = PETSC_FALSE, isolated = PETSC_FALSE;
15: PetscFunctionBeginUser;
16: PetscCall(PetscInitialize(&argc, &args, NULL, help));
17: PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
18: PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
19: PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_vertex_weights", &use_vertex_weights, NULL));
20: PetscCall(PetscOptionsGetBool(NULL, NULL, "-use_edge_weights", &use_edge_weights, NULL));
21: PetscCall(PetscOptionsGetBool(NULL, NULL, "-isolated_process", &isolated, NULL));
23: PetscCheck(size > 2, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "Requires at least three processes");
25: /* Spread the vertices of a path graph over every process but the first, which is left owning no
26: vertices and no edges. Its weight arrays then come back null from a zero-size allocation while
27: the other processes supply real weights, which is the disagreement SCOTCH_dgraphBuild()
28: rejects. Two processes must still own vertices, since
29: PetscPTSCOTCHPartitionGraph_Private() partitions with the sequential SCOTCH_graphBuild() when
30: every vertex lives on one process.
31: Each nonempty process owns several vertices to keep the total vertex load well above the
32: number of parts: PT-SCOTCH divides by a per-part average load that truncates to zero for a
33: graph smaller than the number of parts it is asked for.
35: With -isolated_process the vertices of the last process are isolated instead, so that it owns
36: vertices but no edges. Its edge weight array is then null from a zero-size allocation even
37: though it owns vertices, which the processes that do own edges have to account for. */
38: N = 3 * (size - 1);
39: npath = isolated ? N - 3 : N;
40: n = rank ? 3 : 0;
41: start = rank ? 3 * (rank - 1) : 0;
43: PetscCall(PetscMalloc1(n + 1, &xadj));
44: nz = 0;
45: xadj[0] = 0;
46: for (i = 0; i < n; i++) {
47: v = start + i;
48: if (v < npath) {
49: if (v > 0) nz++;
50: if (v < npath - 1) nz++;
51: }
52: xadj[i + 1] = nz;
53: }
54: PetscCall(PetscMalloc1(nz, &adjncy));
55: nz = 0;
56: for (i = 0; i < n; i++) {
57: v = start + i;
58: if (v < npath) {
59: if (v > 0) adjncy[nz++] = v - 1;
60: if (v < npath - 1) adjncy[nz++] = v + 1;
61: }
62: }
63: if (use_edge_weights && nz) {
64: PetscCall(PetscMalloc1(nz, &eweights));
65: for (i = 0; i < nz; i++) eweights[i] = 2;
66: }
67: if (use_vertex_weights && n) {
68: PetscCall(PetscMalloc1(n, &vweights));
69: for (i = 0; i < n; i++) vweights[i] = rank + 1;
70: }
72: /* MatCreateMPIAdj() takes ownership of xadj, adjncy and eweights, and
73: MatPartitioningSetVertexWeights() takes ownership of vweights */
74: PetscCall(MatCreateMPIAdj(PETSC_COMM_WORLD, n, N, xadj, adjncy, eweights, &adj));
75: PetscCall(MatPartitioningCreate(PETSC_COMM_WORLD, &part));
76: if (use_edge_weights) PetscCall(MatPartitioningSetUseEdgeWeights(part, PETSC_TRUE));
77: PetscCall(MatPartitioningSetAdjacency(part, adj));
78: if (use_vertex_weights) PetscCall(MatPartitioningSetVertexWeights(part, vweights));
79: PetscCall(MatPartitioningSetNParts(part, size));
80: PetscCall(MatPartitioningSetFromOptions(part));
81: PetscCall(MatPartitioningApply(part, &is));
83: /* Which part each vertex lands in depends on the partitioner, but every process must be given
84: the destination of each of its own vertices */
85: PetscCall(ISGetLocalSize(is, &nlocal));
86: PetscCheck(nlocal == n, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Partitioning has %" PetscInt_FMT " local indices, expected %" PetscInt_FMT, nlocal, n);
88: PetscCall(ISDestroy(&is));
89: PetscCall(MatPartitioningDestroy(&part));
90: PetscCall(MatDestroy(&adj));
91: PetscCall(PetscFinalize());
92: return 0;
93: }
95: /*TEST
97: testset:
98: nsize: 3
99: requires: ptscotch
100: args: -mat_partitioning_type ptscotch
101: output_file: output/empty.out
103: test:
104: suffix: vertex_weights
105: args: -use_vertex_weights 1
107: test:
108: suffix: edge_weights
109: args: -use_edge_weights 1
111: test:
112: suffix: both_weights
113: args: -use_vertex_weights 1 -use_edge_weights 1
115: test:
116: suffix: isolated_process
117: args: -isolated_process 1 -use_edge_weights 1
119: TEST*/