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