xref: /petsc/src/dm/impls/plex/plexpartition.c (revision 4b15ede2af8a3e0bc78f86cb79f2c0c764c0a2d7)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 
3 PetscClassId PETSCPARTITIONER_CLASSID = 0;
4 
5 PetscFunctionList PetscPartitionerList              = NULL;
6 PetscBool         PetscPartitionerRegisterAllCalled = PETSC_FALSE;
7 
8 PetscBool ChacoPartitionercite = PETSC_FALSE;
9 const char ChacoPartitionerCitation[] = "@inproceedings{Chaco95,\n"
10                                "  author    = {Bruce Hendrickson and Robert Leland},\n"
11                                "  title     = {A multilevel algorithm for partitioning graphs},\n"
12                                "  booktitle = {Supercomputing '95: Proceedings of the 1995 ACM/IEEE Conference on Supercomputing (CDROM)},"
13                                "  isbn      = {0-89791-816-9},\n"
14                                "  pages     = {28},\n"
15                                "  doi       = {http://doi.acm.org/10.1145/224170.224228},\n"
16                                "  publisher = {ACM Press},\n"
17                                "  address   = {New York},\n"
18                                "  year      = {1995}\n}\n";
19 
20 PetscBool ParMetisPartitionercite = PETSC_FALSE;
21 const char ParMetisPartitionerCitation[] = "@article{KarypisKumar98,\n"
22                                "  author  = {George Karypis and Vipin Kumar},\n"
23                                "  title   = {A Parallel Algorithm for Multilevel Graph Partitioning and Sparse Matrix Ordering},\n"
24                                "  journal = {Journal of Parallel and Distributed Computing},\n"
25                                "  volume  = {48},\n"
26                                "  pages   = {71--85},\n"
27                                "  year    = {1998}\n}\n";
28 
29 #undef __FUNCT__
30 #define __FUNCT__ "DMPlexCreateNeighborCSR"
31 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
32 {
33   const PetscInt maxFaceCases = 30;
34   PetscInt       numFaceCases = 0;
35   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
36   PetscInt      *off, *adj;
37   PetscInt      *neighborCells = NULL;
38   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
39   PetscErrorCode ierr;
40 
41   PetscFunctionBegin;
42   /* For parallel partitioning, I think you have to communicate supports */
43   ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
44   cellDim = dim - cellHeight;
45   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
46   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
47   if (cEnd - cStart == 0) {
48     if (numVertices) *numVertices = 0;
49     if (offsets)   *offsets   = NULL;
50     if (adjacency) *adjacency = NULL;
51     PetscFunctionReturn(0);
52   }
53   numCells  = cEnd - cStart;
54   faceDepth = depth - cellHeight;
55   if (dim == depth) {
56     PetscInt f, fStart, fEnd;
57 
58     ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
59     /* Count neighboring cells */
60     ierr = DMPlexGetHeightStratum(dm, cellHeight+1, &fStart, &fEnd);CHKERRQ(ierr);
61     for (f = fStart; f < fEnd; ++f) {
62       const PetscInt *support;
63       PetscInt        supportSize;
64       ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
65       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
66       if (supportSize == 2) {
67         PetscInt numChildren;
68 
69         ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
70         if (!numChildren) {
71           ++off[support[0]-cStart+1];
72           ++off[support[1]-cStart+1];
73         }
74       }
75     }
76     /* Prefix sum */
77     for (c = 1; c <= numCells; ++c) off[c] += off[c-1];
78     if (adjacency) {
79       PetscInt *tmp;
80 
81       ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
82       ierr = PetscMalloc1((numCells+1), &tmp);CHKERRQ(ierr);
83       ierr = PetscMemcpy(tmp, off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
84       /* Get neighboring cells */
85       for (f = fStart; f < fEnd; ++f) {
86         const PetscInt *support;
87         PetscInt        supportSize;
88         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
89         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
90         if (supportSize == 2) {
91           PetscInt numChildren;
92 
93           ierr = DMPlexGetTreeChildren(dm,f,&numChildren,NULL);CHKERRQ(ierr);
94           if (!numChildren) {
95             adj[tmp[support[0]-cStart]++] = support[1];
96             adj[tmp[support[1]-cStart]++] = support[0];
97           }
98         }
99       }
100 #if defined(PETSC_USE_DEBUG)
101       for (c = 0; c < cEnd-cStart; ++c) if (tmp[c] != off[c+1]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Offset %d != %d for cell %d", tmp[c], off[c], c+cStart);
102 #endif
103       ierr = PetscFree(tmp);CHKERRQ(ierr);
104     }
105     if (numVertices) *numVertices = numCells;
106     if (offsets)   *offsets   = off;
107     if (adjacency) *adjacency = adj;
108     PetscFunctionReturn(0);
109   }
110   /* Setup face recognition */
111   if (faceDepth == 1) {
112     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
113 
114     for (c = cStart; c < cEnd; ++c) {
115       PetscInt corners;
116 
117       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
118       if (!cornersSeen[corners]) {
119         PetscInt nFV;
120 
121         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
122         cornersSeen[corners] = 1;
123 
124         ierr = DMPlexGetNumFaceVertices(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
125 
126         numFaceVertices[numFaceCases++] = nFV;
127       }
128     }
129   }
130   ierr = PetscCalloc1(numCells+1, &off);CHKERRQ(ierr);
131   /* Count neighboring cells */
132   for (cell = cStart; cell < cEnd; ++cell) {
133     PetscInt numNeighbors = PETSC_DETERMINE, n;
134 
135     ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
136     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
137     for (n = 0; n < numNeighbors; ++n) {
138       PetscInt        cellPair[2];
139       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
140       PetscInt        meetSize = 0;
141       const PetscInt *meet    = NULL;
142 
143       cellPair[0] = cell; cellPair[1] = neighborCells[n];
144       if (cellPair[0] == cellPair[1]) continue;
145       if (!found) {
146         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
147         if (meetSize) {
148           PetscInt f;
149 
150           for (f = 0; f < numFaceCases; ++f) {
151             if (numFaceVertices[f] == meetSize) {
152               found = PETSC_TRUE;
153               break;
154             }
155           }
156         }
157         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
158       }
159       if (found) ++off[cell-cStart+1];
160     }
161   }
162   /* Prefix sum */
163   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
164 
165   if (adjacency) {
166     ierr = PetscMalloc1(off[numCells], &adj);CHKERRQ(ierr);
167     /* Get neighboring cells */
168     for (cell = cStart; cell < cEnd; ++cell) {
169       PetscInt numNeighbors = PETSC_DETERMINE, n;
170       PetscInt cellOffset   = 0;
171 
172       ierr = DMPlexGetAdjacency_Internal(dm, cell, PETSC_TRUE, PETSC_FALSE, PETSC_FALSE, &numNeighbors, &neighborCells);CHKERRQ(ierr);
173       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
174       for (n = 0; n < numNeighbors; ++n) {
175         PetscInt        cellPair[2];
176         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
177         PetscInt        meetSize = 0;
178         const PetscInt *meet    = NULL;
179 
180         cellPair[0] = cell; cellPair[1] = neighborCells[n];
181         if (cellPair[0] == cellPair[1]) continue;
182         if (!found) {
183           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
184           if (meetSize) {
185             PetscInt f;
186 
187             for (f = 0; f < numFaceCases; ++f) {
188               if (numFaceVertices[f] == meetSize) {
189                 found = PETSC_TRUE;
190                 break;
191               }
192             }
193           }
194           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
195         }
196         if (found) {
197           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
198           ++cellOffset;
199         }
200       }
201     }
202   }
203   ierr = PetscFree(neighborCells);CHKERRQ(ierr);
204   if (numVertices) *numVertices = numCells;
205   if (offsets)   *offsets   = off;
206   if (adjacency) *adjacency = adj;
207   PetscFunctionReturn(0);
208 }
209 
210 #undef __FUNCT__
211 #define __FUNCT__ "DMPlexEnlargePartition"
212 /* Expand the partition by BFS on the adjacency graph */
213 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection partSection, IS *partition)
214 {
215   PetscHashI      h;
216   const PetscInt *points;
217   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
218   PetscInt        pStart, pEnd, part, q;
219   PetscBool       useCone;
220   PetscErrorCode  ierr;
221 
222   PetscFunctionBegin;
223   PetscHashICreate(h);
224   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
225   ierr = PetscSectionSetChart(partSection, pStart, pEnd);CHKERRQ(ierr);
226   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
227   ierr = PetscMalloc1((pEnd - pStart), &tmpPoints);CHKERRQ(ierr);
228   ierr = DMPlexGetAdjacencyUseCone(dm, &useCone);CHKERRQ(ierr);
229   ierr = DMPlexSetAdjacencyUseCone(dm, PETSC_TRUE);CHKERRQ(ierr);
230   for (part = pStart; part < pEnd; ++part) {
231     PetscInt *adj = NULL;
232     PetscInt  numPoints, nP, numNewPoints, off, p, n = 0;
233 
234     PetscHashIClear(h);
235     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
236     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
237     /* Add all existing points to h */
238     for (p = 0; p < numPoints; ++p) {
239       const PetscInt point = points[off+p];
240       PetscHashIAdd(h, point, 1);
241     }
242     PetscHashISize(h, nP);
243     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
244     /* Add all points in next BFS level */
245     for (p = 0; p < numPoints; ++p) {
246       const PetscInt point   = points[off+p];
247       PetscInt       adjSize = PETSC_DETERMINE, a;
248 
249       ierr = DMPlexGetAdjacency(dm, point, &adjSize, &adj);CHKERRQ(ierr);
250       for (a = 0; a < adjSize; ++a) PetscHashIAdd(h, adj[a], 1);
251     }
252     PetscHashISize(h, numNewPoints);
253     ierr = PetscSectionSetDof(partSection, part, numNewPoints);CHKERRQ(ierr);
254     ierr = PetscMalloc1(numNewPoints, &tmpPoints[part]);CHKERRQ(ierr);
255     ierr = PetscHashIGetKeys(h, &n, tmpPoints[part]);CHKERRQ(ierr);
256     ierr = PetscFree(adj);CHKERRQ(ierr);
257     totPoints += numNewPoints;
258   }
259   ierr = DMPlexSetAdjacencyUseCone(dm, useCone);CHKERRQ(ierr);
260   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
261   PetscHashIDestroy(h);
262   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
263   ierr = PetscMalloc1(totPoints, &newPoints);CHKERRQ(ierr);
264   for (part = pStart, q = 0; part < pEnd; ++part) {
265     PetscInt numPoints, p;
266 
267     ierr = PetscSectionGetDof(partSection, part, &numPoints);CHKERRQ(ierr);
268     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
269     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
270   }
271   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
272   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
273   PetscFunctionReturn(0);
274 }
275 
276 #undef __FUNCT__
277 #define __FUNCT__ "PetscPartitionerRegister"
278 /*@C
279   PetscPartitionerRegister - Adds a new PetscPartitioner implementation
280 
281   Not Collective
282 
283   Input Parameters:
284 + name        - The name of a new user-defined creation routine
285 - create_func - The creation routine itself
286 
287   Notes:
288   PetscPartitionerRegister() may be called multiple times to add several user-defined PetscPartitioners
289 
290   Sample usage:
291 .vb
292     PetscPartitionerRegister("my_part", MyPetscPartitionerCreate);
293 .ve
294 
295   Then, your PetscPartitioner type can be chosen with the procedural interface via
296 .vb
297     PetscPartitionerCreate(MPI_Comm, PetscPartitioner *);
298     PetscPartitionerSetType(PetscPartitioner, "my_part");
299 .ve
300    or at runtime via the option
301 .vb
302     -petscpartitioner_type my_part
303 .ve
304 
305   Level: advanced
306 
307 .keywords: PetscPartitioner, register
308 .seealso: PetscPartitionerRegisterAll(), PetscPartitionerRegisterDestroy()
309 
310 @*/
311 PetscErrorCode PetscPartitionerRegister(const char sname[], PetscErrorCode (*function)(PetscPartitioner))
312 {
313   PetscErrorCode ierr;
314 
315   PetscFunctionBegin;
316   ierr = PetscFunctionListAdd(&PetscPartitionerList, sname, function);CHKERRQ(ierr);
317   PetscFunctionReturn(0);
318 }
319 
320 #undef __FUNCT__
321 #define __FUNCT__ "PetscPartitionerSetType"
322 /*@C
323   PetscPartitionerSetType - Builds a particular PetscPartitioner
324 
325   Collective on PetscPartitioner
326 
327   Input Parameters:
328 + part - The PetscPartitioner object
329 - name - The kind of partitioner
330 
331   Options Database Key:
332 . -petscpartitioner_type <type> - Sets the PetscPartitioner type; use -help for a list of available types
333 
334   Level: intermediate
335 
336 .keywords: PetscPartitioner, set, type
337 .seealso: PetscPartitionerGetType(), PetscPartitionerCreate()
338 @*/
339 PetscErrorCode PetscPartitionerSetType(PetscPartitioner part, PetscPartitionerType name)
340 {
341   PetscErrorCode (*r)(PetscPartitioner);
342   PetscBool      match;
343   PetscErrorCode ierr;
344 
345   PetscFunctionBegin;
346   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
347   ierr = PetscObjectTypeCompare((PetscObject) part, name, &match);CHKERRQ(ierr);
348   if (match) PetscFunctionReturn(0);
349 
350   if (!PetscPartitionerRegisterAllCalled) {ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);}
351   ierr = PetscFunctionListFind(PetscPartitionerList, name, &r);CHKERRQ(ierr);
352   if (!r) SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_UNKNOWN_TYPE, "Unknown PetscPartitioner type: %s", name);
353 
354   if (part->ops->destroy) {
355     ierr              = (*part->ops->destroy)(part);CHKERRQ(ierr);
356     part->ops->destroy = NULL;
357   }
358   ierr = (*r)(part);CHKERRQ(ierr);
359   ierr = PetscObjectChangeTypeName((PetscObject) part, name);CHKERRQ(ierr);
360   PetscFunctionReturn(0);
361 }
362 
363 #undef __FUNCT__
364 #define __FUNCT__ "PetscPartitionerGetType"
365 /*@C
366   PetscPartitionerGetType - Gets the PetscPartitioner type name (as a string) from the object.
367 
368   Not Collective
369 
370   Input Parameter:
371 . part - The PetscPartitioner
372 
373   Output Parameter:
374 . name - The PetscPartitioner type name
375 
376   Level: intermediate
377 
378 .keywords: PetscPartitioner, get, type, name
379 .seealso: PetscPartitionerSetType(), PetscPartitionerCreate()
380 @*/
381 PetscErrorCode PetscPartitionerGetType(PetscPartitioner part, PetscPartitionerType *name)
382 {
383   PetscErrorCode ierr;
384 
385   PetscFunctionBegin;
386   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
387   PetscValidPointer(name, 2);
388   if (!PetscPartitionerRegisterAllCalled) {ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);}
389   *name = ((PetscObject) part)->type_name;
390   PetscFunctionReturn(0);
391 }
392 
393 #undef __FUNCT__
394 #define __FUNCT__ "PetscPartitionerView"
395 /*@C
396   PetscPartitionerView - Views a PetscPartitioner
397 
398   Collective on PetscPartitioner
399 
400   Input Parameter:
401 + part - the PetscPartitioner object to view
402 - v    - the viewer
403 
404   Level: developer
405 
406 .seealso: PetscPartitionerDestroy()
407 @*/
408 PetscErrorCode PetscPartitionerView(PetscPartitioner part, PetscViewer v)
409 {
410   PetscErrorCode ierr;
411 
412   PetscFunctionBegin;
413   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
414   if (!v) {ierr = PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject) part), &v);CHKERRQ(ierr);}
415   if (part->ops->view) {ierr = (*part->ops->view)(part, v);CHKERRQ(ierr);}
416   PetscFunctionReturn(0);
417 }
418 
419 #undef __FUNCT__
420 #define __FUNCT__ "PetscPartitionerViewFromOptions"
421 /*
422   PetscPartitionerViewFromOptions - Processes command line options to determine if/how a PetscPartitioner is to be viewed.
423 
424   Collective on PetscPartitioner
425 
426   Input Parameters:
427 + part   - the PetscPartitioner
428 . prefix - prefix to use for viewing, or NULL
429 - optionname - option to activate viewing
430 
431   Level: intermediate
432 
433 .keywords: PetscPartitioner, view, options, database
434 .seealso: VecViewFromOptions(), MatViewFromOptions()
435 */
436 PetscErrorCode PetscPartitionerViewFromOptions(PetscPartitioner part, const char prefix[], const char optionname[])
437 {
438   PetscViewer       viewer;
439   PetscViewerFormat format;
440   PetscBool         flg;
441   PetscErrorCode    ierr;
442 
443   PetscFunctionBegin;
444   if (prefix) {ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) part), prefix,                       optionname, &viewer, &format, &flg);CHKERRQ(ierr);}
445   else        {ierr = PetscOptionsGetViewer(PetscObjectComm((PetscObject) part), ((PetscObject) part)->prefix, optionname, &viewer, &format, &flg);CHKERRQ(ierr);}
446   if (flg) {
447     ierr = PetscViewerPushFormat(viewer, format);CHKERRQ(ierr);
448     ierr = PetscPartitionerView(part, viewer);CHKERRQ(ierr);
449     ierr = PetscViewerPopFormat(viewer);CHKERRQ(ierr);
450     ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr);
451   }
452   PetscFunctionReturn(0);
453 }
454 #undef __FUNCT__
455 #define __FUNCT__ "PetscPartitionerSetTypeFromOptions_Internal"
456 PetscErrorCode PetscPartitionerSetTypeFromOptions_Internal(PetscPartitioner part)
457 {
458   const char    *defaultType;
459   char           name[256];
460   PetscBool      flg;
461   PetscErrorCode ierr;
462 
463   PetscFunctionBegin;
464   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
465   if (!((PetscObject) part)->type_name) defaultType = PETSCPARTITIONERCHACO;
466   else                                  defaultType = ((PetscObject) part)->type_name;
467   if (!PetscPartitionerRegisterAllCalled) {ierr = PetscPartitionerRegisterAll();CHKERRQ(ierr);}
468 
469   ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr);
470   ierr = PetscOptionsFList("-petscpartitioner_type", "Graph partitioner", "PetscPartitionerSetType", PetscPartitionerList, defaultType, name, 256, &flg);CHKERRQ(ierr);
471   if (flg) {
472     ierr = PetscPartitionerSetType(part, name);CHKERRQ(ierr);
473   } else if (!((PetscObject) part)->type_name) {
474     ierr = PetscPartitionerSetType(part, defaultType);CHKERRQ(ierr);
475   }
476   ierr = PetscOptionsEnd();CHKERRQ(ierr);
477   PetscFunctionReturn(0);
478 }
479 
480 #undef __FUNCT__
481 #define __FUNCT__ "PetscPartitionerSetFromOptions"
482 /*@
483   PetscPartitionerSetFromOptions - sets parameters in a PetscPartitioner from the options database
484 
485   Collective on PetscPartitioner
486 
487   Input Parameter:
488 . part - the PetscPartitioner object to set options for
489 
490   Level: developer
491 
492 .seealso: PetscPartitionerView()
493 @*/
494 PetscErrorCode PetscPartitionerSetFromOptions(PetscPartitioner part)
495 {
496   PetscErrorCode ierr;
497 
498   PetscFunctionBegin;
499   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
500   ierr = PetscPartitionerSetTypeFromOptions_Internal(part);CHKERRQ(ierr);
501 
502   ierr = PetscObjectOptionsBegin((PetscObject) part);CHKERRQ(ierr);
503   if (part->ops->setfromoptions) {ierr = (*part->ops->setfromoptions)(part);CHKERRQ(ierr);}
504   /* process any options handlers added with PetscObjectAddOptionsHandler() */
505   ierr = PetscObjectProcessOptionsHandlers((PetscObject) part);CHKERRQ(ierr);
506   ierr = PetscOptionsEnd();CHKERRQ(ierr);
507   ierr = PetscPartitionerViewFromOptions(part, NULL, "-petscpartitioner_view");CHKERRQ(ierr);
508   PetscFunctionReturn(0);
509 }
510 
511 #undef __FUNCT__
512 #define __FUNCT__ "PetscPartitionerSetUp"
513 /*@C
514   PetscPartitionerSetUp - Construct data structures for the PetscPartitioner
515 
516   Collective on PetscPartitioner
517 
518   Input Parameter:
519 . part - the PetscPartitioner object to setup
520 
521   Level: developer
522 
523 .seealso: PetscPartitionerView(), PetscPartitionerDestroy()
524 @*/
525 PetscErrorCode PetscPartitionerSetUp(PetscPartitioner part)
526 {
527   PetscErrorCode ierr;
528 
529   PetscFunctionBegin;
530   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
531   if (part->ops->setup) {ierr = (*part->ops->setup)(part);CHKERRQ(ierr);}
532   PetscFunctionReturn(0);
533 }
534 
535 #undef __FUNCT__
536 #define __FUNCT__ "PetscPartitionerDestroy"
537 /*@
538   PetscPartitionerDestroy - Destroys a PetscPartitioner object
539 
540   Collective on PetscPartitioner
541 
542   Input Parameter:
543 . part - the PetscPartitioner object to destroy
544 
545   Level: developer
546 
547 .seealso: PetscPartitionerView()
548 @*/
549 PetscErrorCode PetscPartitionerDestroy(PetscPartitioner *part)
550 {
551   PetscErrorCode ierr;
552 
553   PetscFunctionBegin;
554   if (!*part) PetscFunctionReturn(0);
555   PetscValidHeaderSpecific((*part), PETSCPARTITIONER_CLASSID, 1);
556 
557   if (--((PetscObject)(*part))->refct > 0) {*part = 0; PetscFunctionReturn(0);}
558   ((PetscObject) (*part))->refct = 0;
559 
560   if ((*part)->ops->destroy) {ierr = (*(*part)->ops->destroy)(*part);CHKERRQ(ierr);}
561   ierr = PetscHeaderDestroy(part);CHKERRQ(ierr);
562   PetscFunctionReturn(0);
563 }
564 
565 #undef __FUNCT__
566 #define __FUNCT__ "PetscPartitionerCreate"
567 /*@
568   PetscPartitionerCreate - Creates an empty PetscPartitioner object. The type can then be set with PetscPartitionerSetType().
569 
570   Collective on MPI_Comm
571 
572   Input Parameter:
573 . comm - The communicator for the PetscPartitioner object
574 
575   Output Parameter:
576 . part - The PetscPartitioner object
577 
578   Level: beginner
579 
580 .seealso: PetscPartitionerSetType(), PETSCPARTITIONERCHACO, PETSCPARTITIONERPARMETIS, PETSCPARTITIONERSHELL
581 @*/
582 PetscErrorCode PetscPartitionerCreate(MPI_Comm comm, PetscPartitioner *part)
583 {
584   PetscPartitioner p;
585   PetscErrorCode   ierr;
586 
587   PetscFunctionBegin;
588   PetscValidPointer(part, 2);
589   *part = NULL;
590   ierr = PetscFVInitializePackage();CHKERRQ(ierr);
591 
592   ierr = PetscHeaderCreate(p, _p_PetscPartitioner, struct _PetscPartitionerOps, PETSCPARTITIONER_CLASSID, "PetscPartitioner", "Graph Partitioner", "PetscPartitioner", comm, PetscPartitionerDestroy, PetscPartitionerView);CHKERRQ(ierr);
593   ierr = PetscMemzero(p->ops, sizeof(struct _PetscPartitionerOps));CHKERRQ(ierr);
594 
595   *part = p;
596   PetscFunctionReturn(0);
597 }
598 
599 #undef __FUNCT__
600 #define __FUNCT__ "PetscPartitionerPartition"
601 /*@
602   PetscPartitionerPartition - Create a non-overlapping partition of the cells in the mesh
603 
604   Collective on DM
605 
606   Input Parameters:
607 + part    - The PetscPartitioner
608 . dm      - The mesh DM
609 - enlarge - Expand each partition with neighbors
610 
611   Output Parameters:
612 + partSection     - The PetscSection giving the division of points by partition
613 . partition       - The list of points by partition
614 . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
615 - origPartition   - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
616 
617   Note: Instead of cells, points at a given height can be partitioned by calling PetscPartitionerSetPointHeight()
618 
619   Level: developer
620 
621 .seealso DMPlexDistribute(), PetscPartitionerSetPointHeight(), PetscPartitionerCreate()
622 @*/
623 PetscErrorCode PetscPartitionerPartition(PetscPartitioner part, DM dm, PetscBool enlarge, PetscSection partSection, IS *partition, PetscSection origPartSection, IS *origPartition)
624 {
625   PetscMPIInt    size;
626   PetscErrorCode ierr;
627 
628   PetscFunctionBegin;
629   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
630   PetscValidHeaderSpecific(dm, DM_CLASSID, 2);
631   PetscValidHeaderSpecific(partSection, PETSC_SECTION_CLASSID, 4);
632   PetscValidPointer(partition, 5);
633   if (enlarge) {PetscValidHeaderSpecific(origPartSection, PETSC_SECTION_CLASSID, 6);}
634   if (enlarge) {PetscValidPointer(origPartition, 7);}
635   ierr = MPI_Comm_size(PetscObjectComm((PetscObject) part), &size);CHKERRQ(ierr);
636   *origPartition = NULL;
637   if (size == 1) {
638     PetscInt *points;
639     PetscInt  cStart, cEnd, c;
640 
641     ierr = DMPlexGetHeightStratum(dm, part->height, &cStart, &cEnd);CHKERRQ(ierr);
642     ierr = PetscSectionSetChart(partSection, 0, size);CHKERRQ(ierr);
643     ierr = PetscSectionSetDof(partSection, 0, cEnd-cStart);CHKERRQ(ierr);
644     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
645     ierr = PetscMalloc1(cEnd-cStart, &points);CHKERRQ(ierr);
646     for (c = cStart; c < cEnd; ++c) points[c] = c;
647     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
648     PetscFunctionReturn(0);
649   }
650   if (part->height == 0) {
651     PetscInt  numVertices;
652     PetscInt *start     = NULL;
653     PetscInt *adjacency = NULL;
654 
655     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
656     if (!part->ops->partition) SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_WRONGSTATE, "PetscPartitioner has no type");
657     ierr = (*part->ops->partition)(part, dm, size, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
658     if (enlarge) {
659       origPartSection = partSection;
660       *origPartition  = *partition;
661 
662       ierr = DMPlexEnlargePartition(dm, start, adjacency, origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
663     }
664     ierr = PetscFree(start);CHKERRQ(ierr);
665     ierr = PetscFree(adjacency);CHKERRQ(ierr);
666   } else SETERRQ1(PetscObjectComm((PetscObject) part), PETSC_ERR_ARG_OUTOFRANGE, "Invalid height %D for points to partition", part->height);
667   PetscFunctionReturn(0);
668 }
669 
670 #undef __FUNCT__
671 #define __FUNCT__ "PetscPartitionerDestroy_Shell"
672 PetscErrorCode PetscPartitionerDestroy_Shell(PetscPartitioner part)
673 {
674   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
675   PetscErrorCode          ierr;
676 
677   PetscFunctionBegin;
678   ierr = PetscSectionDestroy(&p->section);CHKERRQ(ierr);
679   ierr = ISDestroy(&p->partition);CHKERRQ(ierr);
680   ierr = PetscFree(p);CHKERRQ(ierr);
681   PetscFunctionReturn(0);
682 }
683 
684 #undef __FUNCT__
685 #define __FUNCT__ "PetscPartitionerView_Shell_Ascii"
686 PetscErrorCode PetscPartitionerView_Shell_Ascii(PetscPartitioner part, PetscViewer viewer)
687 {
688   PetscViewerFormat format;
689   PetscErrorCode    ierr;
690 
691   PetscFunctionBegin;
692   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
693   ierr = PetscViewerASCIIPrintf(viewer, "Shell Graph Partitioner:\n");CHKERRQ(ierr);
694   PetscFunctionReturn(0);
695 }
696 
697 #undef __FUNCT__
698 #define __FUNCT__ "PetscPartitionerView_Shell"
699 PetscErrorCode PetscPartitionerView_Shell(PetscPartitioner part, PetscViewer viewer)
700 {
701   PetscBool      iascii;
702   PetscErrorCode ierr;
703 
704   PetscFunctionBegin;
705   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
706   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
707   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
708   if (iascii) {ierr = PetscPartitionerView_Shell_Ascii(part, viewer);CHKERRQ(ierr);}
709   PetscFunctionReturn(0);
710 }
711 
712 #undef __FUNCT__
713 #define __FUNCT__ "PetscPartitionerPartition_Shell"
714 PetscErrorCode PetscPartitionerPartition_Shell(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
715 {
716   PetscPartitioner_Shell *p = (PetscPartitioner_Shell *) part->data;
717   PetscInt                np;
718   PetscErrorCode          ierr;
719 
720   PetscFunctionBegin;
721   if (!numVertices) {
722     ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
723     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
724     ierr = ISCreateGeneral(PetscObjectComm((PetscObject) part), 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
725     PetscFunctionReturn(0);
726   }
727   ierr = PetscSectionGetChart(p->section, NULL, &np);CHKERRQ(ierr);
728   if (nparts != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of requested partitions %d != configured partitions %d", nparts, np);
729   ierr = ISGetLocalSize(p->partition, &np);CHKERRQ(ierr);
730   if (numVertices != np) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Number of input vertices %d != configured vertices %d", numVertices, np);
731   partSection = p->section;
732   ierr = PetscObjectReference((PetscObject) p->section);CHKERRQ(ierr);
733   *partition  = p->partition;
734   ierr = PetscObjectReference((PetscObject) p->partition);CHKERRQ(ierr);
735   PetscFunctionReturn(0);
736 }
737 
738 #undef __FUNCT__
739 #define __FUNCT__ "PetscPartitionerInitialize_Shell"
740 PetscErrorCode PetscPartitionerInitialize_Shell(PetscPartitioner part)
741 {
742   PetscFunctionBegin;
743   part->ops->view      = PetscPartitionerView_Shell;
744   part->ops->destroy   = PetscPartitionerDestroy_Shell;
745   part->ops->partition = PetscPartitionerPartition_Shell;
746   PetscFunctionReturn(0);
747 }
748 
749 /*MC
750   PETSCPARTITIONERSHELL = "shell" - A PetscPartitioner object
751 
752   Level: intermediate
753 
754 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
755 M*/
756 
757 #undef __FUNCT__
758 #define __FUNCT__ "PetscPartitionerCreate_Shell"
759 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Shell(PetscPartitioner part)
760 {
761   PetscPartitioner_Shell *p;
762   PetscErrorCode          ierr;
763 
764   PetscFunctionBegin;
765   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
766   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
767   part->data = p;
768 
769   ierr = PetscPartitionerInitialize_Shell(part);CHKERRQ(ierr);
770   PetscFunctionReturn(0);
771 }
772 
773 #undef __FUNCT__
774 #define __FUNCT__ "PetscPartitionerDestroy_Chaco"
775 PetscErrorCode PetscPartitionerDestroy_Chaco(PetscPartitioner part)
776 {
777   PetscPartitioner_Chaco *p = (PetscPartitioner_Chaco *) part->data;
778   PetscErrorCode          ierr;
779 
780   PetscFunctionBegin;
781   ierr = PetscFree(p);CHKERRQ(ierr);
782   PetscFunctionReturn(0);
783 }
784 
785 #undef __FUNCT__
786 #define __FUNCT__ "PetscPartitionerView_Chaco_Ascii"
787 PetscErrorCode PetscPartitionerView_Chaco_Ascii(PetscPartitioner part, PetscViewer viewer)
788 {
789   PetscViewerFormat format;
790   PetscErrorCode    ierr;
791 
792   PetscFunctionBegin;
793   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
794   ierr = PetscViewerASCIIPrintf(viewer, "Chaco Graph Partitioner:\n");CHKERRQ(ierr);
795   PetscFunctionReturn(0);
796 }
797 
798 #undef __FUNCT__
799 #define __FUNCT__ "PetscPartitionerView_Chaco"
800 PetscErrorCode PetscPartitionerView_Chaco(PetscPartitioner part, PetscViewer viewer)
801 {
802   PetscBool      iascii;
803   PetscErrorCode ierr;
804 
805   PetscFunctionBegin;
806   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
807   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
808   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
809   if (iascii) {ierr = PetscPartitionerView_Chaco_Ascii(part, viewer);CHKERRQ(ierr);}
810   PetscFunctionReturn(0);
811 }
812 
813 #if defined(PETSC_HAVE_CHACO)
814 #if defined(PETSC_HAVE_UNISTD_H)
815 #include <unistd.h>
816 #endif
817 /* Chaco does not have an include file */
818 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
819                        float *ewgts, float *x, float *y, float *z, char *outassignname,
820                        char *outfilename, short *assignment, int architecture, int ndims_tot,
821                        int mesh_dims[3], double *goal, int global_method, int local_method,
822                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
823 
824 extern int FREE_GRAPH;
825 #endif
826 
827 #undef __FUNCT__
828 #define __FUNCT__ "PetscPartitionerPartition_Chaco"
829 PetscErrorCode PetscPartitionerPartition_Chaco(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
830 {
831 #if defined(PETSC_HAVE_CHACO)
832   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
833   MPI_Comm       comm;
834   int            nvtxs          = numVertices; /* number of vertices in full graph */
835   int           *vwgts          = NULL;   /* weights for all vertices */
836   float         *ewgts          = NULL;   /* weights for all edges */
837   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
838   char          *outassignname  = NULL;   /*  name of assignment output file */
839   char          *outfilename    = NULL;   /* output file name */
840   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
841   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
842   int            mesh_dims[3];            /* dimensions of mesh of processors */
843   double        *goal          = NULL;    /* desired set sizes for each set */
844   int            global_method = 1;       /* global partitioning algorithm */
845   int            local_method  = 1;       /* local partitioning algorithm */
846   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
847   int            vmax          = 200;     /* how many vertices to coarsen down to? */
848   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
849   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
850   long           seed          = 123636512; /* for random graph mutations */
851   short int     *assignment;              /* Output partition */
852   int            fd_stdout, fd_pipe[2];
853   PetscInt      *points;
854   int            i, v, p;
855   PetscErrorCode ierr;
856 
857   PetscFunctionBegin;
858   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
859   if (!numVertices) {
860     ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
861     ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
862     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
863     PetscFunctionReturn(0);
864   }
865   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
866   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
867 
868   if (global_method == INERTIAL_METHOD) {
869     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
870     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
871   }
872   mesh_dims[0] = nparts;
873   mesh_dims[1] = 1;
874   mesh_dims[2] = 1;
875   ierr = PetscMalloc1(nvtxs, &assignment);CHKERRQ(ierr);
876   /* Chaco outputs to stdout. We redirect this to a buffer. */
877   /* TODO: check error codes for UNIX calls */
878 #if defined(PETSC_HAVE_UNISTD_H)
879   {
880     int piperet;
881     piperet = pipe(fd_pipe);
882     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
883     fd_stdout = dup(1);
884     close(1);
885     dup2(fd_pipe[1], 1);
886   }
887 #endif
888   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
889                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
890                    vmax, ndims, eigtol, seed);
891 #if defined(PETSC_HAVE_UNISTD_H)
892   {
893     char msgLog[10000];
894     int  count;
895 
896     fflush(stdout);
897     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
898     if (count < 0) count = 0;
899     msgLog[count] = 0;
900     close(1);
901     dup2(fd_stdout, 1);
902     close(fd_stdout);
903     close(fd_pipe[0]);
904     close(fd_pipe[1]);
905     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
906   }
907 #endif
908   /* Convert to PetscSection+IS */
909   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
910   for (v = 0; v < nvtxs; ++v) {
911     ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);
912   }
913   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
914   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
915   for (p = 0, i = 0; p < nparts; ++p) {
916     for (v = 0; v < nvtxs; ++v) {
917       if (assignment[v] == p) points[i++] = v;
918     }
919   }
920   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
921   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
922   if (global_method == INERTIAL_METHOD) {
923     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
924   }
925   ierr = PetscFree(assignment);CHKERRQ(ierr);
926   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
927   PetscFunctionReturn(0);
928 #else
929   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-chaco.");
930 #endif
931 }
932 
933 #undef __FUNCT__
934 #define __FUNCT__ "PetscPartitionerInitialize_Chaco"
935 PetscErrorCode PetscPartitionerInitialize_Chaco(PetscPartitioner part)
936 {
937   PetscFunctionBegin;
938   part->ops->view      = PetscPartitionerView_Chaco;
939   part->ops->destroy   = PetscPartitionerDestroy_Chaco;
940   part->ops->partition = PetscPartitionerPartition_Chaco;
941   PetscFunctionReturn(0);
942 }
943 
944 /*MC
945   PETSCPARTITIONERCHACO = "chaco" - A PetscPartitioner object using the Chaco library
946 
947   Level: intermediate
948 
949 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
950 M*/
951 
952 #undef __FUNCT__
953 #define __FUNCT__ "PetscPartitionerCreate_Chaco"
954 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_Chaco(PetscPartitioner part)
955 {
956   PetscPartitioner_Chaco *p;
957   PetscErrorCode          ierr;
958 
959   PetscFunctionBegin;
960   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
961   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
962   part->data = p;
963 
964   ierr = PetscPartitionerInitialize_Chaco(part);CHKERRQ(ierr);
965   ierr = PetscCitationsRegister(ChacoPartitionerCitation, &ChacoPartitionercite);CHKERRQ(ierr);
966   PetscFunctionReturn(0);
967 }
968 
969 #undef __FUNCT__
970 #define __FUNCT__ "PetscPartitionerDestroy_ParMetis"
971 PetscErrorCode PetscPartitionerDestroy_ParMetis(PetscPartitioner part)
972 {
973   PetscPartitioner_ParMetis *p = (PetscPartitioner_ParMetis *) part->data;
974   PetscErrorCode             ierr;
975 
976   PetscFunctionBegin;
977   ierr = PetscFree(p);CHKERRQ(ierr);
978   PetscFunctionReturn(0);
979 }
980 
981 #undef __FUNCT__
982 #define __FUNCT__ "PetscPartitionerView_ParMetis_Ascii"
983 PetscErrorCode PetscPartitionerView_ParMetis_Ascii(PetscPartitioner part, PetscViewer viewer)
984 {
985   PetscViewerFormat format;
986   PetscErrorCode    ierr;
987 
988   PetscFunctionBegin;
989   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
990   ierr = PetscViewerASCIIPrintf(viewer, "ParMetis Graph Partitioner:\n");CHKERRQ(ierr);
991   PetscFunctionReturn(0);
992 }
993 
994 #undef __FUNCT__
995 #define __FUNCT__ "PetscPartitionerView_ParMetis"
996 PetscErrorCode PetscPartitionerView_ParMetis(PetscPartitioner part, PetscViewer viewer)
997 {
998   PetscBool      iascii;
999   PetscErrorCode ierr;
1000 
1001   PetscFunctionBegin;
1002   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1003   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1004   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
1005   if (iascii) {ierr = PetscPartitionerView_ParMetis_Ascii(part, viewer);CHKERRQ(ierr);}
1006   PetscFunctionReturn(0);
1007 }
1008 
1009 #if defined(PETSC_HAVE_PARMETIS)
1010 #include <parmetis.h>
1011 #endif
1012 
1013 #undef __FUNCT__
1014 #define __FUNCT__ "PetscPartitionerPartition_ParMetis"
1015 PetscErrorCode PetscPartitionerPartition_ParMetis(PetscPartitioner part, DM dm, PetscInt nparts, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection partSection, IS *partition)
1016 {
1017 #if defined(PETSC_HAVE_PARMETIS)
1018   MPI_Comm       comm;
1019   PetscInt       nvtxs      = numVertices; /* The number of vertices in full graph */
1020   PetscInt      *vtxdist;                  /* Distribution of vertices across processes */
1021   PetscInt      *xadj       = start;       /* Start of edge list for each vertex */
1022   PetscInt      *adjncy     = adjacency;   /* Edge lists for all vertices */
1023   PetscInt      *vwgt       = NULL;        /* Vertex weights */
1024   PetscInt      *adjwgt     = NULL;        /* Edge weights */
1025   PetscInt       wgtflag    = 0;           /* Indicates which weights are present */
1026   PetscInt       numflag    = 0;           /* Indicates initial offset (0 or 1) */
1027   PetscInt       ncon       = 1;           /* The number of weights per vertex */
1028   PetscReal     *tpwgts;                   /* The fraction of vertex weights assigned to each partition */
1029   PetscReal     *ubvec;                    /* The balance intolerance for vertex weights */
1030   PetscInt       options[5];               /* Options */
1031   /* Outputs */
1032   PetscInt       edgeCut;                  /* The number of edges cut by the partition */
1033   PetscInt      *assignment, *points;
1034   PetscMPIInt    rank, p, v, i;
1035   PetscErrorCode ierr;
1036 
1037   PetscFunctionBegin;
1038   ierr = PetscObjectGetComm((PetscObject) part, &comm);CHKERRQ(ierr);
1039   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
1040   options[0] = 0; /* Use all defaults */
1041   /* Calculate vertex distribution */
1042   ierr = PetscMalloc4(nparts+1,&vtxdist,nparts*ncon,&tpwgts,ncon,&ubvec,nvtxs,&assignment);CHKERRQ(ierr);
1043   vtxdist[0] = 0;
1044   ierr = MPI_Allgather(&nvtxs, 1, MPIU_INT, &vtxdist[1], 1, MPIU_INT, comm);CHKERRQ(ierr);
1045   for (p = 2; p <= nparts; ++p) {
1046     vtxdist[p] += vtxdist[p-1];
1047   }
1048   /* Calculate weights */
1049   for (p = 0; p < nparts; ++p) {
1050     tpwgts[p] = 1.0/nparts;
1051   }
1052   ubvec[0] = 1.05;
1053 
1054   if (nparts == 1) {
1055     ierr = PetscMemzero(assignment, nvtxs * sizeof(PetscInt));
1056   } else {
1057     if (vtxdist[1] == vtxdist[nparts]) {
1058       if (!rank) {
1059         PetscStackPush("METIS_PartGraphKway");
1060         ierr = METIS_PartGraphKway(&nvtxs, &ncon, xadj, adjncy, vwgt, NULL, adjwgt, &nparts, tpwgts, ubvec, NULL, &edgeCut, assignment);
1061         PetscStackPop;
1062         if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in METIS_PartGraphKway()");
1063       }
1064     } else {
1065       PetscStackPush("ParMETIS_V3_PartKway");
1066       ierr = ParMETIS_V3_PartKway(vtxdist, xadj, adjncy, vwgt, adjwgt, &wgtflag, &numflag, &ncon, &nparts, tpwgts, ubvec, options, &edgeCut, assignment, &comm);
1067       PetscStackPop;
1068       if (ierr != METIS_OK) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in ParMETIS_V3_PartKway()");
1069     }
1070   }
1071   /* Convert to PetscSection+IS */
1072   ierr = PetscSectionSetChart(partSection, 0, nparts);CHKERRQ(ierr);
1073   for (v = 0; v < nvtxs; ++v) {ierr = PetscSectionAddDof(partSection, assignment[v], 1);CHKERRQ(ierr);}
1074   ierr = PetscSectionSetUp(partSection);CHKERRQ(ierr);
1075   ierr = PetscMalloc1(nvtxs, &points);CHKERRQ(ierr);
1076   for (p = 0, i = 0; p < nparts; ++p) {
1077     for (v = 0; v < nvtxs; ++v) {
1078       if (assignment[v] == p) points[i++] = v;
1079     }
1080   }
1081   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
1082   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
1083   ierr = PetscFree4(vtxdist,tpwgts,ubvec,assignment);CHKERRQ(ierr);
1084 #else
1085   SETERRQ(PetscObjectComm((PetscObject) part), PETSC_ERR_SUP, "Mesh partitioning needs external package support.\nPlease reconfigure with --download-parmetis.");
1086 #endif
1087   PetscFunctionReturn(0);
1088 }
1089 
1090 #undef __FUNCT__
1091 #define __FUNCT__ "PetscPartitionerInitialize_ParMetis"
1092 PetscErrorCode PetscPartitionerInitialize_ParMetis(PetscPartitioner part)
1093 {
1094   PetscFunctionBegin;
1095   part->ops->view      = PetscPartitionerView_ParMetis;
1096   part->ops->destroy   = PetscPartitionerDestroy_ParMetis;
1097   part->ops->partition = PetscPartitionerPartition_ParMetis;
1098   PetscFunctionReturn(0);
1099 }
1100 
1101 /*MC
1102   PETSCPARTITIONERPARMETIS = "parmetis" - A PetscPartitioner object using the ParMetis library
1103 
1104   Level: intermediate
1105 
1106 .seealso: PetscPartitionerType, PetscPartitionerCreate(), PetscPartitionerSetType()
1107 M*/
1108 
1109 #undef __FUNCT__
1110 #define __FUNCT__ "PetscPartitionerCreate_ParMetis"
1111 PETSC_EXTERN PetscErrorCode PetscPartitionerCreate_ParMetis(PetscPartitioner part)
1112 {
1113   PetscPartitioner_ParMetis *p;
1114   PetscErrorCode          ierr;
1115 
1116   PetscFunctionBegin;
1117   PetscValidHeaderSpecific(part, PETSCPARTITIONER_CLASSID, 1);
1118   ierr       = PetscNewLog(part, &p);CHKERRQ(ierr);
1119   part->data = p;
1120 
1121   ierr = PetscPartitionerInitialize_ParMetis(part);CHKERRQ(ierr);
1122   ierr = PetscCitationsRegister(ParMetisPartitionerCitation, &ParMetisPartitionercite);CHKERRQ(ierr);
1123   PetscFunctionReturn(0);
1124 }
1125 
1126 #undef __FUNCT__
1127 #define __FUNCT__ "DMPlexMarkTreeClosure"
1128 static PetscErrorCode DMPlexMarkTreeClosure(DM dm, PetscSegBuffer segpart, PetscBT bt, PetscInt point, PetscInt *partSize)
1129 {
1130   PetscInt       parent, closureSize, *closure = NULL, i, pStart, pEnd;
1131   PetscErrorCode ierr;
1132 
1133   PetscFunctionBegin;
1134   ierr = DMPlexGetTreeParent(dm,point,&parent,NULL);CHKERRQ(ierr);
1135   if (parent == point) PetscFunctionReturn(0);
1136   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
1137   ierr = DMPlexGetTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1138   for (i = 0; i < closureSize; i++) {
1139     PetscInt cpoint = closure[2*i];
1140 
1141     if (!PetscBTLookupSet(bt,cpoint-pStart)) {
1142       PetscInt *PETSC_RESTRICT pt;
1143       (*partSize)++;
1144       ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr);
1145       *pt = cpoint;
1146     }
1147     ierr = DMPlexMarkTreeClosure(dm,segpart,bt,cpoint,partSize);CHKERRQ(ierr);
1148   }
1149   ierr = DMPlexRestoreTransitiveClosure(dm,parent,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1150   PetscFunctionReturn(0);
1151 }
1152 
1153 #undef __FUNCT__
1154 #define __FUNCT__ "DMPlexCreatePartitionClosure"
1155 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
1156 {
1157   /* const PetscInt  height = 0; */
1158   const PetscInt *partArray;
1159   PetscInt       *allPoints, *packPoints;
1160   PetscInt        rStart, rEnd, rank, pStart, pEnd, newSize;
1161   PetscErrorCode  ierr;
1162   PetscBT         bt;
1163   PetscSegBuffer  segpack,segpart;
1164 
1165   PetscFunctionBegin;
1166   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
1167   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
1168   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
1169   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
1170   ierr = DMPlexGetChart(dm,&pStart,&pEnd);CHKERRQ(ierr);
1171   ierr = PetscBTCreate(pEnd-pStart,&bt);CHKERRQ(ierr);
1172   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpack);CHKERRQ(ierr);
1173   ierr = PetscSegBufferCreate(sizeof(PetscInt),1000,&segpart);CHKERRQ(ierr);
1174   for (rank = rStart; rank < rEnd; ++rank) {
1175     PetscInt partSize = 0, numPoints, offset, p, *PETSC_RESTRICT placePoints;
1176 
1177     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
1178     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
1179     for (p = 0; p < numPoints; ++p) {
1180       PetscInt  point   = partArray[offset+p], closureSize, c;
1181       PetscInt *closure = NULL;
1182 
1183       /* TODO Include support for height > 0 case */
1184       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1185       for (c=0; c<closureSize; c++) {
1186         PetscInt cpoint = closure[c*2];
1187         if (!PetscBTLookupSet(bt,cpoint-pStart)) {
1188           PetscInt *PETSC_RESTRICT pt;
1189           partSize++;
1190           ierr = PetscSegBufferGetInts(segpart,1,&pt);CHKERRQ(ierr);
1191           *pt = cpoint;
1192         }
1193         ierr = DMPlexMarkTreeClosure(dm,segpart,bt,cpoint,&partSize);CHKERRQ(ierr);
1194       }
1195       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
1196     }
1197     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
1198     ierr = PetscSegBufferGetInts(segpack,partSize,&placePoints);CHKERRQ(ierr);
1199     ierr = PetscSegBufferExtractTo(segpart,placePoints);CHKERRQ(ierr);
1200     ierr = PetscSortInt(partSize,placePoints);CHKERRQ(ierr);
1201     for (p=0; p<partSize; p++) {ierr = PetscBTClear(bt,placePoints[p]-pStart);CHKERRQ(ierr);}
1202   }
1203   ierr = PetscBTDestroy(&bt);CHKERRQ(ierr);
1204   ierr = PetscSegBufferDestroy(&segpart);CHKERRQ(ierr);
1205 
1206   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
1207   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
1208   ierr = PetscMalloc1(newSize, &allPoints);CHKERRQ(ierr);
1209 
1210   ierr = PetscSegBufferExtractInPlace(segpack,&packPoints);CHKERRQ(ierr);
1211   for (rank = rStart; rank < rEnd; ++rank) {
1212     PetscInt numPoints, offset;
1213 
1214     ierr = PetscSectionGetDof(*section, rank, &numPoints);CHKERRQ(ierr);
1215     ierr = PetscSectionGetOffset(*section, rank, &offset);CHKERRQ(ierr);
1216     ierr = PetscMemcpy(&allPoints[offset], packPoints, numPoints * sizeof(PetscInt));CHKERRQ(ierr);
1217     packPoints += numPoints;
1218   }
1219 
1220   ierr = PetscSegBufferDestroy(&segpack);CHKERRQ(ierr);
1221   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
1222   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
1223   PetscFunctionReturn(0);
1224 }
1225