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