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