xref: /petsc/src/dm/partitioner/interface/partitioner.c (revision dbbe0bcd3f3a8fbab5a45420dc06f8387e5764c6)
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   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(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   PetscTryTypeMethod(part,view, 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   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(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   PetscTryTypeMethod(part,setup);
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   PetscTryTypeMethod(part,reset);
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   PetscTryTypeMethod((*part),destroy);
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 PetscUseTypeMethod(part,partition , nparts, numVertices, start, adjacency, vertexSection, targetSection, partSection, partition);
325   PetscCall(PetscSectionSetUp(partSection));
326   if (part->viewerGraph) {
327     PetscViewer viewer = part->viewerGraph;
328     PetscBool   isascii;
329     PetscInt    v, i;
330     PetscMPIInt rank;
331 
332     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject) viewer), &rank));
333     PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii));
334     if (isascii) {
335       PetscCall(PetscViewerASCIIPushSynchronized(viewer));
336       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]Nv: %" PetscInt_FMT "\n", rank, numVertices));
337       for (v = 0; v < numVertices; ++v) {
338         const PetscInt s = start[v];
339         const PetscInt e = start[v+1];
340 
341         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%d]  ", rank));
342         for (i = s; i < e; ++i) PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "%" PetscInt_FMT " ", adjacency[i]));
343         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "[%" PetscInt_FMT "-%" PetscInt_FMT ")\n", s, e));
344       }
345       PetscCall(PetscViewerFlush(viewer));
346       PetscCall(PetscViewerASCIIPopSynchronized(viewer));
347     }
348   }
349   if (part->viewer) PetscCall(PetscPartitionerView(part,part->viewer));
350   PetscFunctionReturn(0);
351 }
352 
353 /*@
354   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
355 
356   Collective
357 
358   Input Parameter:
359 . comm - The communicator for the PetscPartitioner object
360 
361   Output Parameter:
362 . part - The PetscPartitioner object
363 
364   Level: beginner
365 
366 .seealso: `PetscPartitionerSetType()`, `PetscPartitionerDestroy()`
367 @*/
368 PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
369 {
370   PetscPartitioner p;
371   const char       *partitionerType = NULL;
372 
373   PetscFunctionBegin;
374   PetscValidPointer(part, 2);
375   *part = NULL;
376   PetscCall(PetscPartitionerInitializePackage());
377 
378   PetscCall(PetscHeaderCreate(p, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView));
379   PetscCall(PetscPartitionerGetDefaultType(comm, &partitionerType));
380   PetscCall(PetscPartitionerSetType(p, partitionerType));
381 
382   p->edgeCut = 0;
383   p->balance = 0.0;
384   p->usevwgt = PETSC_TRUE;
385 
386   *part = p;
387   PetscFunctionReturn(0);
388 }
389