xref: /petsc/src/dm/partitioner/interface/partitioner.c (revision 237137dc2c36cd704ae82eca1d03b531ce3d02f9)
1 #include <petsc/private/partitionerimpl.h> /*I "petscpartitioner.h" I*/
2 
3 /*@
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 @*/
PetscPartitionerSetType(PetscPartitioner part,PetscPartitionerType name)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 /*@
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 @*/
PetscPartitionerGetType(PetscPartitioner part,PetscPartitionerType * name)65 PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name)
66 {
67   PetscFunctionBegin;
68   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
69   PetscAssertPointer(name, 2);
70   *name = ((PetscObject)part)->type_name;
71   PetscFunctionReturn(PETSC_SUCCESS);
72 }
73 
74 /*@
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 @*/
PetscPartitionerViewFromOptions(PetscPartitioner A,PetscObject obj,const char name[])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 @*/
PetscPartitionerView(PetscPartitioner part,PetscViewer v)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 && part->printHeader) {
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     PetscCall(PetscViewerASCIIPrintf(v, "  use edge weights: %d\n", part->useewgt));
129   }
130   PetscTryTypeMethod(part, view, v);
131   PetscFunctionReturn(PETSC_SUCCESS);
132 }
133 
PetscPartitionerGetDefaultType(MPI_Comm comm,const char ** defaultType)134 static PetscErrorCode PetscPartitionerGetDefaultType(MPI_Comm comm, const char **defaultType)
135 {
136   PetscMPIInt size;
137 
138   PetscFunctionBegin;
139   PetscCallMPI(MPI_Comm_size(comm, &size));
140   if (size == 1) {
141     *defaultType = PETSCPARTITIONERSIMPLE;
142   } else {
143 #if defined(PETSC_HAVE_PARMETIS)
144     *defaultType = PETSCPARTITIONERPARMETIS;
145 #elif defined(PETSC_HAVE_PTSCOTCH)
146     *defaultType = PETSCPARTITIONERPTSCOTCH;
147 #elif defined(PETSC_HAVE_CHACO)
148     *defaultType = PETSCPARTITIONERCHACO;
149 #else
150     *defaultType = PETSCPARTITIONERSIMPLE;
151 #endif
152   }
153   PetscFunctionReturn(PETSC_SUCCESS);
154 }
155 
156 /*@
157   PetscPartitionerSetFromOptions - sets parameters in a `PetscPartitioner` from the options database
158 
159   Collective
160 
161   Input Parameter:
162 . part - the `PetscPartitioner` object to set options for
163 
164   Options Database Keys:
165 + -petscpartitioner_type <type>        - Sets the `PetscPartitioner` type; use -help for a list of available types
166 . -petscpartitioner_use_vertex_weights - Uses weights associated with the graph vertices
167 - -petscpartitioner_view_graph         - View the graph each time PetscPartitionerPartition is called. Viewer can be customized, see `PetscOptionsCreateViewer()`
168 
169   Level: developer
170 
171 .seealso: `PetscPartitionerView()`, `PetscPartitionerSetType()`, `PetscPartitionerPartition()`
172 @*/
PetscPartitionerSetFromOptions(PetscPartitioner part)173 PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part)
174 {
175   const char *currentType = NULL;
176   char        name[256];
177   PetscBool   flg;
178 
179   PetscFunctionBegin;
180   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
181   PetscObjectOptionsBegin((PetscObject)part);
182   PetscCall(PetscPartitionerGetType(part, &currentType));
183   PetscCall(PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, currentType, name, sizeof(name), &flg));
184   if (flg) PetscCall(PetscPartitionerSetType(part, name));
185   PetscCall(PetscOptionsBool("-petscpartitioner_use_vertex_weights", "Use vertex weights", "", part->usevwgt, &part->usevwgt, NULL));
186   PetscCall(PetscOptionsBool("-petscpartitioner_use_edge_weights", "Use edge weights", "", part->useewgt, &part->useewgt, NULL));
187   PetscTryTypeMethod(part, setfromoptions, PetscOptionsObject);
188   PetscCall(PetscViewerDestroy(&part->viewer));
189   PetscCall(PetscViewerDestroy(&part->viewerGraph));
190   PetscCall(PetscOptionsCreateViewer(((PetscObject)part)->comm, ((PetscObject)part)->options, ((PetscObject)part)->prefix, "-petscpartitioner_view", &part->viewer, &part->viewerFmt, NULL));
191   PetscCall(PetscOptionsCreateViewer(((PetscObject)part)->comm, ((PetscObject)part)->options, ((PetscObject)part)->prefix, "-petscpartitioner_view_graph", &part->viewerGraph, NULL, NULL));
192   /* process any options handlers added with PetscObjectAddOptionsHandler() */
193   PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)part, PetscOptionsObject));
194   PetscOptionsEnd();
195   PetscFunctionReturn(PETSC_SUCCESS);
196 }
197 
198 /*@
199   PetscPartitionerSetUp - Construct data structures for the `PetscPartitioner`
200 
201   Collective
202 
203   Input Parameter:
204 . part - the `PetscPartitioner` object to setup
205 
206   Level: developer
207 
208 .seealso: `PetscPartitionerView()`, `PetscPartitionerDestroy()`
209 @*/
PetscPartitionerSetUp(PetscPartitioner part)210 PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part)
211 {
212   PetscFunctionBegin;
213   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
214   PetscTryTypeMethod(part, setup);
215   PetscFunctionReturn(PETSC_SUCCESS);
216 }
217 
218 /*@
219   PetscPartitionerReset - Resets data structures for the `PetscPartitioner`
220 
221   Collective
222 
223   Input Parameter:
224 . part - the `PetscPartitioner` object to reset
225 
226   Level: developer
227 
228 .seealso: `PetscPartitionerSetUp()`, `PetscPartitionerDestroy()`
229 @*/
PetscPartitionerReset(PetscPartitioner part)230 PetscErrorCode PetscPartitionerReset(PetscPartitioner part)
231 {
232   PetscFunctionBegin;
233   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
234   PetscTryTypeMethod(part, reset);
235   PetscFunctionReturn(PETSC_SUCCESS);
236 }
237 
238 /*@
239   PetscPartitionerDestroy - Destroys a `PetscPartitioner` object
240 
241   Collective
242 
243   Input Parameter:
244 . part - the `PetscPartitioner` object to destroy
245 
246   Level: developer
247 
248 .seealso: `PetscPartitionerView()`
249 @*/
PetscPartitionerDestroy(PetscPartitioner * part)250 PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part)
251 {
252   PetscFunctionBegin;
253   if (!*part) PetscFunctionReturn(PETSC_SUCCESS);
254   PetscValidHeaderSpecific(*part, PETSCPARTITIONER_CLASSID, 1);
255 
256   if (--((PetscObject)*part)->refct > 0) {
257     *part = NULL;
258     PetscFunctionReturn(PETSC_SUCCESS);
259   }
260   ((PetscObject)*part)->refct = 0;
261 
262   PetscCall(PetscPartitionerReset(*part));
263 
264   PetscCall(PetscViewerDestroy(&(*part)->viewer));
265   PetscCall(PetscViewerDestroy(&(*part)->viewerGraph));
266   PetscTryTypeMethod(*part, destroy);
267   PetscCall(PetscHeaderDestroy(part));
268   PetscFunctionReturn(PETSC_SUCCESS);
269 }
270 
271 /*@
272   PetscPartitionerPartition - Partition a graph
273 
274   Collective
275 
276   Input Parameters:
277 + part          - The `PetscPartitioner`
278 . nparts        - Number of partitions
279 . numVertices   - Number of vertices in the local part of the graph
280 . start         - row pointers for the local part of the graph (CSR style)
281 . adjacency     - adjacency list (CSR style)
282 . vertexSection - PetscSection describing the absolute weight of each local vertex (can be `NULL`)
283 . edgeSection   - PetscSection describing the absolute weight of each local edge (can be `NULL`)
284 - targetSection - PetscSection describing the absolute weight of each partition (can be `NULL`)
285 
286   Output Parameters:
287 + partSection - The `PetscSection` giving the division of points by partition
288 - partition   - The list of points by partition
289 
290   Options Database Keys:
291 + -petscpartitioner_view       - View the partitioner information
292 - -petscpartitioner_view_graph - View the graph we are partitioning
293 
294   Level: developer
295 
296   Notes:
297   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.
298   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.
299 
300 .seealso: `PetscPartitionerCreate()`, `PetscPartitionerSetType()`, `PetscSectionCreate()`, `PetscSectionSetChart()`, `PetscSectionSetDof()`
301 @*/
PetscPartitionerPartition(PetscPartitioner part,PetscInt nparts,PetscInt numVertices,PetscInt start[],PetscInt adjacency[],PetscSection vertexSection,PetscSection edgeSection,PetscSection targetSection,PetscSection partSection,IS * partition)302 PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertexSection, PetscSection edgeSection, PetscSection targetSection, PetscSection partSection, IS *partition)
303 {
304   PetscFunctionBegin;
305   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
306   PetscValidLogicalCollectiveInt(part, nparts, 2);
307   PetscCheck(nparts > 0, PetscObjectComm((PetscObject)part), PETSC_ERR_ARG_OUTOFRANGE, "Number of parts must be positive");
308   PetscCheck(numVertices >= 0, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices must be non-negative");
309   if (numVertices && !part->noGraph) {
310     PetscAssertPointer(start, 4);
311     PetscAssertPointer(start + numVertices, 4);
312     if (start[numVertices]) PetscAssertPointer(adjacency, 5);
313   }
314   if (vertexSection) {
315     PetscInt s, e;
316 
317     PetscValidHeaderSpecific(vertexSection, PETSC_SECTION_CLASSID, 6);
318     PetscCall(PetscSectionGetChart(vertexSection, &s, &e));
319     PetscCheck(s <= 0 && e >= numVertices, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid vertexSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")", s, e);
320   }
321   if (edgeSection) {
322     PetscInt s, e;
323 
324     PetscValidHeaderSpecific(edgeSection, PETSC_SECTION_CLASSID, 7);
325     PetscCall(PetscSectionGetChart(edgeSection, &s, &e));
326     PetscCheck(s <= 0 && e >= start[numVertices], PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid edgeSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")", s, e);
327   }
328   if (targetSection) {
329     PetscInt s, e;
330 
331     PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 8);
332     PetscCall(PetscSectionGetChart(targetSection, &s, &e));
333     PetscCheck(s <= 0 && e >= nparts, PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid targetSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")", s, e);
334   }
335   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 9);
336   PetscAssertPointer(partition, 10);
337 
338   PetscCall(PetscSectionReset(partSection));
339   PetscCall(PetscSectionSetChart(partSection, 0, nparts));
340   if (nparts == 1) { /* quick */
341     PetscCall(PetscSectionSetDof(partSection, 0, numVertices));
342     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)part), numVertices, 0, 1, partition));
343   } else PetscUseTypeMethod(part, partition, nparts, numVertices, start, adjacency, vertexSection, edgeSection, targetSection, partSection, partition);
344   PetscCall(PetscSectionSetUp(partSection));
345   if (part->viewerGraph) {
346     PetscViewer viewer = part->viewerGraph;
347     PetscBool   isascii;
348     PetscInt    v, i;
349     PetscMPIInt rank;
350 
351     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)viewer), &rank));
352     PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
353     if (isascii) {
354       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
355       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %" PetscInt_FMT "\n", rank, numVertices));
356       for (v = 0; v < numVertices; ++v) {
357         const PetscInt s = start[v];
358         const PetscInt e = start[v + 1];
359 
360         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]  ", rank));
361         for (i = s; i < e; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT " ", adjacency[i]));
362         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%" PetscInt_FMT "-%" PetscInt_FMT ")\n", s, e));
363       }
364       PetscCall(PetscViewerFlush(viewer));
365       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
366     }
367   }
368   if (part->viewer) {
369     PetscCall(PetscViewerPushFormat(part->viewer, part->viewerFmt));
370     PetscCall(PetscPartitionerView(part, part->viewer));
371     PetscCall(PetscViewerPopFormat(part->viewer));
372   }
373   PetscFunctionReturn(PETSC_SUCCESS);
374 }
375 
376 /*@
377   PetscPartitionerCreate - Creates an empty `PetscPartitioner` object. The type can then be set with `PetscPartitionerSetType()`.
378 
379   Collective
380 
381   Input Parameter:
382 . comm - The communicator for the `PetscPartitioner` object
383 
384   Output Parameter:
385 . part - The `PetscPartitioner` object
386 
387   Level: beginner
388 
389 .seealso: `PetscPartitionerSetType()`, `PetscPartitionerDestroy()`
390 @*/
PetscPartitionerCreate(MPI_Comm comm,PetscPartitioner * part)391 PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
392 {
393   PetscPartitioner p;
394   const char      *partitionerType = NULL;
395 
396   PetscFunctionBegin;
397   PetscAssertPointer(part, 2);
398   *part = NULL;
399   PetscCall(PetscPartitionerInitializePackage());
400 
401   PetscCall(PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView));
402   PetscCall(PetscPartitionerGetDefaultType(comm, &partitionerType));
403   PetscCall(PetscPartitionerSetType(p, partitionerType));
404 
405   p->usevwgt     = PETSC_TRUE;
406   p->printHeader = PETSC_TRUE;
407 
408   *part = p;
409   PetscFunctionReturn(PETSC_SUCCESS);
410 }
411