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