xref: /petsc/src/dm/partitioner/interface/partitioner.c (revision 2e65eb737b5b07432530db55f6b2a145ebc548b2)
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(0);
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   if (part->ops->destroy) {
41     PetscCall((*part->ops->destroy)(part));
42   }
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(0);
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(0);
72 }
73 
74 /*@C
75    PetscPartitionerViewFromOptions - View from Options
76 
77    Collective on PetscPartitioner
78 
79    Input Parameters:
80 +  A - the PetscPartitioner object
81 .  obj - Optional object
82 -  name - command line option
83 
84    Level: intermediate
85 .seealso:  PetscPartitionerView(), PetscObjectViewFromOptions()
86 @*/
87 PetscErrorCode PetscPartitionerViewFromOptions(PetscPartitioner A,PetscObject obj,const char name[])
88 {
89   PetscFunctionBegin;
90   PetscValidHeaderSpecific(A,PETSCPARTITIONER_CLASSID,1);
91   PetscCall(PetscObjectViewFromOptions((PetscObject)A,obj,name));
92   PetscFunctionReturn(0);
93 }
94 
95 /*@
96   PetscPartitionerView - Views a PetscPartitioner
97 
98   Collective on PetscPartitioner
99 
100   Input Parameters:
101 + part - the PetscPartitioner object to view
102 - v    - the viewer
103 
104   Level: developer
105 
106 .seealso: PetscPartitionerDestroy()
107 @*/
108 PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v)
109 {
110   PetscMPIInt    size;
111   PetscBool      isascii;
112 
113   PetscFunctionBegin;
114   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
115   if (!v) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v));
116   PetscCall(PetscObjectTypeCompare((PetscObject) v, PETSCVIEWERASCII, &isascii));
117   if (isascii) {
118     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject) part), &size));
119     PetscCall(PetscViewerASCIIPrintf(v, "Graph Partitioner: %d MPI Process%s\n", size, size > 1 ? "es" : ""));
120     PetscCall(PetscViewerASCIIPrintf(v, "  type: %s\n", ((PetscObject)part)->type_name));
121     PetscCall(PetscViewerASCIIPrintf(v, "  edge cut: %" PetscInt_FMT "\n", part->edgeCut));
122     PetscCall(PetscViewerASCIIPrintf(v, "  balance: %.2g\n", (double)part->balance));
123     PetscCall(PetscViewerASCIIPrintf(v, "  use vertex weights: %d\n", part->usevwgt));
124   }
125   if (part->ops->view) PetscCall((*part->ops->view)(part, v));
126   PetscFunctionReturn(0);
127 }
128 
129 static PetscErrorCode PetscPartitionerGetDefaultType(MPI_Comm comm, const char **defaultType)
130 {
131   PetscMPIInt    size;
132 
133   PetscFunctionBegin;
134   PetscCallMPI(MPI_Comm_size(comm, &size));
135   if (size == 1) {
136     *defaultType = PETSCPARTITIONERSIMPLE;
137   } else {
138 #if defined(PETSC_HAVE_PARMETIS)
139     *defaultType = PETSCPARTITIONERPARMETIS;
140 #elif defined(PETSC_HAVE_PTSCOTCH)
141     *defaultType = PETSCPARTITIONERPTSCOTCH;
142 #elif defined(PETSC_HAVE_CHACO)
143     *defaultType = PETSCPARTITIONERCHACO;
144 #else
145     *defaultType = PETSCPARTITIONERSIMPLE;
146 #endif
147   }
148   PetscFunctionReturn(0);
149 }
150 
151 /*@
152   PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database
153 
154   Collective on PetscPartitioner
155 
156   Input Parameter:
157 . part - the PetscPartitioner object to set options for
158 
159   Options Database Keys:
160 +  -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types
161 .  -petscpartitioner_use_vertex_weights - Uses weights associated with the graph vertices
162 -  -petscpartitioner_view_graph - View the graph each time PetscPartitionerPartition is called. Viewer can be customized, see PetscOptionsGetViewer()
163 
164   Level: developer
165 
166 .seealso: PetscPartitionerView(), PetscPartitionerSetType(), PetscPartitionerPartition()
167 @*/
168 PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part)
169 {
170   const char    *currentType = NULL;
171   char           name[256];
172   PetscBool      flg;
173 
174   PetscFunctionBegin;
175   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
176   PetscObjectOptionsBegin((PetscObject) part);
177   PetscCall(PetscPartitionerGetType(part, &currentType));
178   PetscCall(PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, currentType, name, sizeof(name), &flg));
179   if (flg) {
180     PetscCall(PetscPartitionerSetType(part, name));
181   }
182   PetscCall(PetscOptionsBool("-petscpartitioner_use_vertex_weights","Use vertex weights","",part->usevwgt,&part->usevwgt,NULL));
183   if (part->ops->setfromoptions) {
184     PetscCall((*part->ops->setfromoptions)(PetscOptionsObject,part));
185   }
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(PetscOptionsObject,(PetscObject) part));
192   PetscOptionsEnd();
193   PetscFunctionReturn(0);
194 }
195 
196 /*@
197   PetscPartitionerSetUp - Construct data structures for the PetscPartitioner
198 
199   Collective on PetscPartitioner
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   if (part->ops->setup) PetscCall((*part->ops->setup)(part));
213   PetscFunctionReturn(0);
214 }
215 
216 /*@
217   PetscPartitionerReset - Resets data structures for the PetscPartitioner
218 
219   Collective on PetscPartitioner
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   if (part->ops->reset) PetscCall((*part->ops->reset)(part));
233   PetscFunctionReturn(0);
234 }
235 
236 /*@
237   PetscPartitionerDestroy - Destroys a PetscPartitioner object
238 
239   Collective on PetscPartitioner
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(0);
252   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
253 
254   if (--((PetscObject)(*part))->refct > 0) {*part = NULL; PetscFunctionReturn(0);}
255   ((PetscObject) (*part))->refct = 0;
256 
257   PetscCall(PetscPartitionerReset(*part));
258 
259   PetscCall(PetscViewerDestroy(&(*part)->viewer));
260   PetscCall(PetscViewerDestroy(&(*part)->viewerGraph));
261   if ((*part)->ops->destroy) PetscCall((*(*part)->ops->destroy)(*part));
262   PetscCall(PetscHeaderDestroy(part));
263   PetscFunctionReturn(0);
264 }
265 
266 /*@
267   PetscPartitionerPartition - Partition a graph
268 
269   Collective on PetscPartitioner
270 
271   Input Parameters:
272 + part    - The PetscPartitioner
273 . nparts  - Number of partitions
274 . numVertices - Number of vertices in the local part of the graph
275 . start - row pointers for the local part of the graph (CSR style)
276 . adjacency - adjacency list (CSR style)
277 . vertexSection - PetscSection describing the absolute weight of each local vertex (can be NULL)
278 - targetSection - PetscSection describing the absolute weight of each partition (can be NULL)
279 
280   Output Parameters:
281 + partSection     - The PetscSection giving the division of points by partition
282 - partition       - The list of points by partition
283 
284   Options Database:
285 + -petscpartitioner_view - View the partitioner information
286 - -petscpartitioner_view_graph - View the graph we are partitioning
287 
288   Notes:
289     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.
290     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.
291 
292   Level: developer
293 
294 .seealso PetscPartitionerCreate(), PetscPartitionerSetType(), PetscSectionCreate(), PetscSectionSetChart(), PetscSectionSetDof()
295 @*/
296 PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertexSection, PetscSection targetSection, PetscSection partSection, IS *partition)
297 {
298   PetscFunctionBegin;
299   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
300   PetscValidLogicalCollectiveInt(part, nparts, 2);
301   PetscCheck(nparts > 0,PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Number of parts must be positive");
302   PetscCheck(numVertices >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices must be non-negative");
303   if (numVertices && !part->noGraph) {
304     PetscValidIntPointer(start, 4);
305     PetscValidIntPointer(start + numVertices, 4);
306     if (start[numVertices]) PetscValidIntPointer(adjacency, 5);
307   }
308   if (vertexSection) {
309     PetscInt s,e;
310 
311     PetscValidHeaderSpecific(vertexSection, PETSC_SECTION_CLASSID, 6);
312     PetscCall(PetscSectionGetChart(vertexSection, &s, &e));
313     PetscCheckFalse(s > 0 || e < numVertices,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Invalid vertexSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")",s,e);
314   }
315   if (targetSection) {
316     PetscInt s,e;
317 
318     PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 7);
319     PetscCall(PetscSectionGetChart(targetSection, &s, &e));
320     PetscCheckFalse(s > 0 || e < nparts,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Invalid targetSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")",s,e);
321   }
322   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 8);
323   PetscValidPointer(partition, 9);
324 
325   PetscCall(PetscSectionReset(partSection));
326   PetscCall(PetscSectionSetChart(partSection, 0, nparts));
327   if (nparts == 1) { /* quick */
328     PetscCall(PetscSectionSetDof(partSection, 0, numVertices));
329     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)part),numVertices,0,1,partition));
330   } else {
331     PetscCheck(part->ops->partition,PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "PetscPartitioner %s has no partitioning method", ((PetscObject)part)->type_name);
332     PetscCall((*part->ops->partition)(part, nparts, numVertices, start, adjacency, vertexSection, targetSection, partSection, partition));
333   }
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) {
359     PetscCall(PetscPartitionerView(part,part->viewer));
360   }
361   PetscFunctionReturn(0);
362 }
363 
364 /*@
365   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
366 
367   Collective
368 
369   Input Parameter:
370 . comm - The communicator for the PetscPartitioner object
371 
372   Output Parameter:
373 . part - The PetscPartitioner object
374 
375   Level: beginner
376 
377 .seealso: PetscPartitionerSetType(), PetscPartitionerDestroy()
378 @*/
379 PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
380 {
381   PetscPartitioner p;
382   const char       *partitionerType = NULL;
383 
384   PetscFunctionBegin;
385   PetscValidPointer(part, 2);
386   *part = NULL;
387   PetscCall(PetscPartitionerInitializePackage());
388 
389   PetscCall(PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView));
390   PetscCall(PetscPartitionerGetDefaultType(comm, &partitionerType));
391   PetscCall(PetscPartitionerSetType(p, partitionerType));
392 
393   p->edgeCut = 0;
394   p->balance = 0.0;
395   p->usevwgt = PETSC_TRUE;
396 
397   *part = p;
398   PetscFunctionReturn(0);
399 }
400