xref: /petsc/src/dm/partitioner/interface/partitioner.c (revision ffa8c5705e8ab2cf85ee1d14dbe507a6e2eb5283)
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: %D\n", part->edgeCut));
122     PetscCall(PetscViewerASCIIPrintf(v, "  balance: %.2g\n", 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   PetscErrorCode ierr;
174 
175   PetscFunctionBegin;
176   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
177   ierr = PetscObjectOptionsBegin((PetscObject) part);PetscCall(ierr);
178   PetscCall(PetscPartitionerGetType(part, &currentType));
179   PetscCall(PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, currentType, name, sizeof(name), &flg));
180   if (flg) {
181     PetscCall(PetscPartitionerSetType(part, name));
182   }
183   PetscCall(PetscOptionsBool("-petscpartitioner_use_vertex_weights","Use vertex weights","",part->usevwgt,&part->usevwgt,NULL));
184   if (part->ops->setfromoptions) {
185     PetscCall((*part->ops->setfromoptions)(PetscOptionsObject,part));
186   }
187   PetscCall(PetscViewerDestroy(&part->viewer));
188   PetscCall(PetscViewerDestroy(&part->viewerGraph));
189   PetscCall(PetscOptionsGetViewer(((PetscObject) part)->comm, ((PetscObject) part)->options, ((PetscObject) part)->prefix, "-petscpartitioner_view", &part->viewer, NULL, NULL));
190   PetscCall(PetscOptionsGetViewer(((PetscObject) part)->comm, ((PetscObject) part)->options, ((PetscObject) part)->prefix, "-petscpartitioner_view_graph", &part->viewerGraph, NULL, &part->viewGraph));
191   /* process any options handlers added with PetscObjectAddOptionsHandler() */
192   PetscCall(PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) part));
193   ierr = PetscOptionsEnd();PetscCall(ierr);
194   PetscFunctionReturn(0);
195 }
196 
197 /*@
198   PetscPartitionerSetUp - Construct data structures for the PetscPartitioner
199 
200   Collective on PetscPartitioner
201 
202   Input Parameter:
203 . part - the PetscPartitioner object to setup
204 
205   Level: developer
206 
207 .seealso: PetscPartitionerView(), PetscPartitionerDestroy()
208 @*/
209 PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part)
210 {
211   PetscFunctionBegin;
212   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
213   if (part->ops->setup) PetscCall((*part->ops->setup)(part));
214   PetscFunctionReturn(0);
215 }
216 
217 /*@
218   PetscPartitionerReset - Resets data structures for the PetscPartitioner
219 
220   Collective on PetscPartitioner
221 
222   Input Parameter:
223 . part - the PetscPartitioner object to reset
224 
225   Level: developer
226 
227 .seealso: PetscPartitionerSetUp(), PetscPartitionerDestroy()
228 @*/
229 PetscErrorCode PetscPartitionerReset(PetscPartitioner part)
230 {
231   PetscFunctionBegin;
232   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
233   if (part->ops->reset) PetscCall((*part->ops->reset)(part));
234   PetscFunctionReturn(0);
235 }
236 
237 /*@
238   PetscPartitionerDestroy - Destroys a PetscPartitioner object
239 
240   Collective on PetscPartitioner
241 
242   Input Parameter:
243 . part - the PetscPartitioner object to destroy
244 
245   Level: developer
246 
247 .seealso: PetscPartitionerView()
248 @*/
249 PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part)
250 {
251   PetscFunctionBegin;
252   if (!*part) PetscFunctionReturn(0);
253   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
254 
255   if (--((PetscObject)(*part))->refct > 0) {*part = NULL; PetscFunctionReturn(0);}
256   ((PetscObject) (*part))->refct = 0;
257 
258   PetscCall(PetscPartitionerReset(*part));
259 
260   PetscCall(PetscViewerDestroy(&(*part)->viewer));
261   PetscCall(PetscViewerDestroy(&(*part)->viewerGraph));
262   if ((*part)->ops->destroy) PetscCall((*(*part)->ops->destroy)(*part));
263   PetscCall(PetscHeaderDestroy(part));
264   PetscFunctionReturn(0);
265 }
266 
267 /*@
268   PetscPartitionerPartition - Partition a graph
269 
270   Collective on PetscPartitioner
271 
272   Input Parameters:
273 + part    - The PetscPartitioner
274 . nparts  - Number of partitions
275 . numVertices - Number of vertices in the local part of the graph
276 . start - row pointers for the local part of the graph (CSR style)
277 . adjacency - adjacency list (CSR style)
278 . vertexSection - PetscSection describing the absolute weight of each local vertex (can be NULL)
279 - targetSection - PetscSection describing the absolute weight of each partition (can be NULL)
280 
281   Output Parameters:
282 + partSection     - The PetscSection giving the division of points by partition
283 - partition       - The list of points by partition
284 
285   Options Database:
286 + -petscpartitioner_view - View the partitioner information
287 - -petscpartitioner_view_graph - View the graph we are partitioning
288 
289   Notes:
290     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.
291     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.
292 
293   Level: developer
294 
295 .seealso PetscPartitionerCreate(), PetscPartitionerSetType(), PetscSectionCreate(), PetscSectionSetChart(), PetscSectionSetDof()
296 @*/
297 PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertexSection, PetscSection targetSection, PetscSection partSection, IS *partition)
298 {
299   PetscFunctionBegin;
300   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
301   PetscValidLogicalCollectiveInt(part, nparts, 2);
302   PetscCheckFalse(nparts <= 0,PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Number of parts must be positive");
303   PetscCheckFalse(numVertices < 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices must be non-negative");
304   if (numVertices && !part->noGraph) {
305     PetscValidIntPointer(start, 4);
306     PetscValidIntPointer(start + numVertices, 4);
307     if (start[numVertices]) PetscValidIntPointer(adjacency, 5);
308   }
309   if (vertexSection) {
310     PetscInt s,e;
311 
312     PetscValidHeaderSpecific(vertexSection, PETSC_SECTION_CLASSID, 6);
313     PetscCall(PetscSectionGetChart(vertexSection, &s, &e));
314     PetscCheckFalse(s > 0 || e < numVertices,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Invalid vertexSection chart [%D,%D)",s,e);
315   }
316   if (targetSection) {
317     PetscInt s,e;
318 
319     PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 7);
320     PetscCall(PetscSectionGetChart(targetSection, &s, &e));
321     PetscCheckFalse(s > 0 || e < nparts,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Invalid targetSection chart [%D,%D)",s,e);
322   }
323   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 8);
324   PetscValidPointer(partition, 9);
325 
326   PetscCall(PetscSectionReset(partSection));
327   PetscCall(PetscSectionSetChart(partSection, 0, nparts));
328   if (nparts == 1) { /* quick */
329     PetscCall(PetscSectionSetDof(partSection, 0, numVertices));
330     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)part),numVertices,0,1,partition));
331   } else {
332     PetscCheck(part->ops->partition,PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "PetscPartitioner %s has no partitioning method", ((PetscObject)part)->type_name);
333     PetscCall((*part->ops->partition)(part, nparts, numVertices, start, adjacency, vertexSection, targetSection, partSection, partition));
334   }
335   PetscCall(PetscSectionSetUp(partSection));
336   if (part->viewerGraph) {
337     PetscViewer viewer = part->viewerGraph;
338     PetscBool   isascii;
339     PetscInt    v, i;
340     PetscMPIInt rank;
341 
342     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) viewer), &rank));
343     PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii));
344     if (isascii) {
345       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
346       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %D\n", rank, numVertices));
347       for (v = 0; v < numVertices; ++v) {
348         const PetscInt s = start[v];
349         const PetscInt e = start[v+1];
350 
351         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]  ", rank));
352         for (i = s; i < e; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%D ", adjacency[i]));
353         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%D-%D)\n", s, e));
354       }
355       PetscCall(PetscViewerFlush(viewer));
356       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
357     }
358   }
359   if (part->viewer) {
360     PetscCall(PetscPartitionerView(part,part->viewer));
361   }
362   PetscFunctionReturn(0);
363 }
364 
365 /*@
366   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
367 
368   Collective
369 
370   Input Parameter:
371 . comm - The communicator for the PetscPartitioner object
372 
373   Output Parameter:
374 . part - The PetscPartitioner object
375 
376   Level: beginner
377 
378 .seealso: PetscPartitionerSetType(), PetscPartitionerDestroy()
379 @*/
380 PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
381 {
382   PetscPartitioner p;
383   const char       *partitionerType = NULL;
384 
385   PetscFunctionBegin;
386   PetscValidPointer(part, 2);
387   *part = NULL;
388   PetscCall(PetscPartitionerInitializePackage());
389 
390   PetscCall(PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView));
391   PetscCall(PetscPartitionerGetDefaultType(comm, &partitionerType));
392   PetscCall(PetscPartitionerSetType(p, partitionerType));
393 
394   p->edgeCut = 0;
395   p->balance = 0.0;
396   p->usevwgt = PETSC_TRUE;
397 
398   *part = p;
399   PetscFunctionReturn(0);
400 }
401