xref: /petsc/src/dm/partitioner/interface/partitioner.c (revision ebead697dbf761eb322f829370bbe90b3bd93fa3)
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) PetscCall((*part->ops->destroy)(part));
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(0);
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(0);
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(0);
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   if (part->ops->view) PetscCall((*part->ops->view)(part, v));
124   PetscFunctionReturn(0);
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(0);
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   if (part->ops->setfromoptions) PetscCall((*part->ops->setfromoptions)(PetscOptionsObject,part));
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(PetscOptionsObject,(PetscObject) part));
186   PetscOptionsEnd();
187   PetscFunctionReturn(0);
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   if (part->ops->setup) PetscCall((*part->ops->setup)(part));
207   PetscFunctionReturn(0);
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   if (part->ops->reset) PetscCall((*part->ops->reset)(part));
227   PetscFunctionReturn(0);
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(0);
246   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
247 
248   if (--((PetscObject)(*part))->refct > 0) {*part = NULL; PetscFunctionReturn(0);}
249   ((PetscObject) (*part))->refct = 0;
250 
251   PetscCall(PetscPartitionerReset(*part));
252 
253   PetscCall(PetscViewerDestroy(&(*part)->viewer));
254   PetscCall(PetscViewerDestroy(&(*part)->viewerGraph));
255   if ((*part)->ops->destroy) PetscCall((*(*part)->ops->destroy)(*part));
256   PetscCall(PetscHeaderDestroy(part));
257   PetscFunctionReturn(0);
258 }
259 
260 /*@
261   PetscPartitionerPartition - Partition a graph
262 
263   Collective on PetscPartitioner
264 
265   Input Parameters:
266 + part    - The PetscPartitioner
267 . nparts  - Number of partitions
268 . numVertices - Number of vertices in the local part of the graph
269 . start - row pointers for the local part of the graph (CSR style)
270 . adjacency - adjacency list (CSR style)
271 . vertexSection - PetscSection describing the absolute weight of each local vertex (can be NULL)
272 - targetSection - PetscSection describing the absolute weight of each partition (can be NULL)
273 
274   Output Parameters:
275 + partSection     - The PetscSection giving the division of points by partition
276 - partition       - The list of points by partition
277 
278   Options Database:
279 + -petscpartitioner_view - View the partitioner information
280 - -petscpartitioner_view_graph - View the graph we are partitioning
281 
282   Notes:
283     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.
284     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.
285 
286   Level: developer
287 
288 .seealso `PetscPartitionerCreate()`, `PetscPartitionerSetType()`, `PetscSectionCreate()`, `PetscSectionSetChart()`, `PetscSectionSetDof()`
289 @*/
290 PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection vertexSection, PetscSection targetSection, PetscSection partSection, IS *partition)
291 {
292   PetscFunctionBegin;
293   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
294   PetscValidLogicalCollectiveInt(part, nparts, 2);
295   PetscCheck(nparts > 0,PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Number of parts must be positive");
296   PetscCheck(numVertices >= 0,PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices must be non-negative");
297   if (numVertices && !part->noGraph) {
298     PetscValidIntPointer(start, 4);
299     PetscValidIntPointer(start + numVertices, 4);
300     if (start[numVertices]) PetscValidIntPointer(adjacency, 5);
301   }
302   if (vertexSection) {
303     PetscInt s,e;
304 
305     PetscValidHeaderSpecific(vertexSection, PETSC_SECTION_CLASSID, 6);
306     PetscCall(PetscSectionGetChart(vertexSection, &s, &e));
307     PetscCheck(s <= 0 && e >= numVertices,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Invalid vertexSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")",s,e);
308   }
309   if (targetSection) {
310     PetscInt s,e;
311 
312     PetscValidHeaderSpecific(targetSection, PETSC_SECTION_CLASSID, 7);
313     PetscCall(PetscSectionGetChart(targetSection, &s, &e));
314     PetscCheck(s <= 0 && e >= nparts,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Invalid targetSection chart [%" PetscInt_FMT ",%" PetscInt_FMT ")",s,e);
315   }
316   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 8);
317   PetscValidPointer(partition, 9);
318 
319   PetscCall(PetscSectionReset(partSection));
320   PetscCall(PetscSectionSetChart(partSection, 0, nparts));
321   if (nparts == 1) { /* quick */
322     PetscCall(PetscSectionSetDof(partSection, 0, numVertices));
323     PetscCall(ISCreateStride(PetscObjectComm((PetscObject)part),numVertices,0,1,partition));
324   } else {
325     PetscCheck(part->ops->partition,PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "PetscPartitioner %s has no partitioning method", ((PetscObject)part)->type_name);
326     PetscCall((*part->ops->partition)(part, nparts, numVertices, start, adjacency, vertexSection, targetSection, partSection, partition));
327   }
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(0);
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(0);
391 }
392