xref: /petsc/src/dm/impls/plex/plexdistribute.c (revision 0c8c14c502e79aaeb7ec26e1cd1e476322d9010e)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <petscsf.h>
3 
4 #undef __FUNCT__
5 #define __FUNCT__ "DMPlexSetAdjacencyUseCone"
6 /*@
7   DMPlexSetAdjacencyUseCone - Define adjacency in the mesh using either the cone or the support first
8 
9   Input Parameters:
10 + dm      - The DM object
11 - useCone - Flag to use the cone first
12 
13   Level: intermediate
14 
15   Notes:
16 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
17 $     FVM:   Two points p and q are adjacent if q \in star(cone(p)),    useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
18 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
19 
20 .seealso: DMPlexGetAdjacencyUseCone(), DMPlexSetAdjacencyUseClosure(), DMPlexGetAdjacencyUseClosure(), DMPlexDistribute(), DMPlexPreallocateOperator()
21 @*/
22 PetscErrorCode DMPlexSetAdjacencyUseCone(DM dm, PetscBool useCone)
23 {
24   DM_Plex *mesh = (DM_Plex *) dm->data;
25 
26   PetscFunctionBegin;
27   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
28   mesh->useCone = useCone;
29   PetscFunctionReturn(0);
30 }
31 
32 #undef __FUNCT__
33 #define __FUNCT__ "DMPlexGetAdjacencyUseCone"
34 /*@
35   DMPlexGetAdjacencyUseCone - Query whether adjacency in the mesh uses the cone or the support first
36 
37   Input Parameter:
38 . dm      - The DM object
39 
40   Output Parameter:
41 . useCone - Flag to use the cone first
42 
43   Level: intermediate
44 
45   Notes:
46 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
47 $     FVM:   Two points p and q are adjacent if q \in star(cone(p)),    useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
48 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
49 
50 .seealso: DMPlexSetAdjacencyUseCone(), DMPlexSetAdjacencyUseClosure(), DMPlexGetAdjacencyUseClosure(), DMPlexDistribute(), DMPlexPreallocateOperator()
51 @*/
52 PetscErrorCode DMPlexGetAdjacencyUseCone(DM dm, PetscBool *useCone)
53 {
54   DM_Plex *mesh = (DM_Plex *) dm->data;
55 
56   PetscFunctionBegin;
57   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
58   PetscValidIntPointer(useCone, 2);
59   *useCone = mesh->useCone;
60   PetscFunctionReturn(0);
61 }
62 
63 #undef __FUNCT__
64 #define __FUNCT__ "DMPlexSetAdjacencyUseClosure"
65 /*@
66   DMPlexSetAdjacencyUseClosure - Define adjacency in the mesh using the transitive closure
67 
68   Input Parameters:
69 + dm      - The DM object
70 - useClosure - Flag to use the closure
71 
72   Level: intermediate
73 
74   Notes:
75 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
76 $     FVM:   Two points p and q are adjacent if q \in star(cone(p)),    useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
77 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
78 
79 .seealso: DMPlexGetAdjacencyUseClosure(), DMPlexSetAdjacencyUseCone(), DMPlexGetAdjacencyUseCone(), DMPlexDistribute(), DMPlexPreallocateOperator()
80 @*/
81 PetscErrorCode DMPlexSetAdjacencyUseClosure(DM dm, PetscBool useClosure)
82 {
83   DM_Plex *mesh = (DM_Plex *) dm->data;
84 
85   PetscFunctionBegin;
86   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
87   mesh->useClosure = useClosure;
88   PetscFunctionReturn(0);
89 }
90 
91 #undef __FUNCT__
92 #define __FUNCT__ "DMPlexGetAdjacencyUseClosure"
93 /*@
94   DMPlexGetAdjacencyUseClosure - Query whether adjacency in the mesh uses the transitive closure
95 
96   Input Parameter:
97 . dm      - The DM object
98 
99   Output Parameter:
100 . useClosure - Flag to use the closure
101 
102   Level: intermediate
103 
104   Notes:
105 $     FEM:   Two points p and q are adjacent if q \in closure(star(p)), useCone = PETSC_FALSE, useClosure = PETSC_TRUE
106 $     FVM:   Two points p and q are adjacent if q \in star(cone(p)),    useCone = PETSC_TRUE,  useClosure = PETSC_FALSE
107 $     FVM++: Two points p and q are adjacent if q \in star(closure(p)), useCone = PETSC_TRUE,  useClosure = PETSC_TRUE
108 
109 .seealso: DMPlexSetAdjacencyUseClosure(), DMPlexSetAdjacencyUseCone(), DMPlexGetAdjacencyUseCone(), DMPlexDistribute(), DMPlexPreallocateOperator()
110 @*/
111 PetscErrorCode DMPlexGetAdjacencyUseClosure(DM dm, PetscBool *useClosure)
112 {
113   DM_Plex *mesh = (DM_Plex *) dm->data;
114 
115   PetscFunctionBegin;
116   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
117   PetscValidIntPointer(useClosure, 2);
118   *useClosure = mesh->useClosure;
119   PetscFunctionReturn(0);
120 }
121 
122 #undef __FUNCT__
123 #define __FUNCT__ "DMPlexGetAdjacency_Cone_Internal"
124 static PetscErrorCode DMPlexGetAdjacency_Cone_Internal(DM dm, PetscInt p, PetscInt *adjSize, PetscInt adj[])
125 {
126   const PetscInt *cone = NULL;
127   PetscInt        numAdj = 0, maxAdjSize = *adjSize, coneSize, c;
128   PetscErrorCode  ierr;
129 
130   PetscFunctionBeginHot;
131   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
132   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
133   for (c = 0; c < coneSize; ++c) {
134     const PetscInt *support = NULL;
135     PetscInt        supportSize, s, q;
136 
137     ierr = DMPlexGetSupportSize(dm, cone[c], &supportSize);CHKERRQ(ierr);
138     ierr = DMPlexGetSupport(dm, cone[c], &support);CHKERRQ(ierr);
139     for (s = 0; s < supportSize; ++s) {
140       for (q = 0; q < numAdj || (adj[numAdj++] = support[s],0); ++q) {
141         if (support[s] == adj[q]) break;
142       }
143       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
144     }
145   }
146   *adjSize = numAdj;
147   PetscFunctionReturn(0);
148 }
149 
150 #undef __FUNCT__
151 #define __FUNCT__ "DMPlexGetAdjacency_Support_Internal"
152 static PetscErrorCode DMPlexGetAdjacency_Support_Internal(DM dm, PetscInt p, PetscInt *adjSize, PetscInt adj[])
153 {
154   const PetscInt *support = NULL;
155   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
156   PetscErrorCode  ierr;
157 
158   PetscFunctionBeginHot;
159   ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
160   ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
161   for (s = 0; s < supportSize; ++s) {
162     const PetscInt *cone = NULL;
163     PetscInt        coneSize, c, q;
164 
165     ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
166     ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
167     for (c = 0; c < coneSize; ++c) {
168       for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
169         if (cone[c] == adj[q]) break;
170       }
171       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
172     }
173   }
174   *adjSize = numAdj;
175   PetscFunctionReturn(0);
176 }
177 
178 #undef __FUNCT__
179 #define __FUNCT__ "DMPlexGetAdjacency_Transitive_Internal"
180 static PetscErrorCode DMPlexGetAdjacency_Transitive_Internal(DM dm, PetscInt p, PetscBool useClosure, PetscInt *adjSize, PetscInt adj[])
181 {
182   PetscInt      *star = NULL;
183   PetscInt       numAdj = 0, maxAdjSize = *adjSize, starSize, s;
184   PetscErrorCode ierr;
185 
186   PetscFunctionBeginHot;
187   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, &star);CHKERRQ(ierr);
188   for (s = 0; s < starSize*2; s += 2) {
189     const PetscInt *closure = NULL;
190     PetscInt        closureSize, c, q;
191 
192     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
193     for (c = 0; c < closureSize*2; c += 2) {
194       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
195         if (closure[c] == adj[q]) break;
196       }
197       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
198     }
199     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
200   }
201   ierr = DMPlexRestoreTransitiveClosure(dm, p, useClosure, &starSize, &star);CHKERRQ(ierr);
202   *adjSize = numAdj;
203   PetscFunctionReturn(0);
204 }
205 
206 #undef __FUNCT__
207 #define __FUNCT__ "DMPlexGetAdjacency_Internal"
208 PetscErrorCode DMPlexGetAdjacency_Internal(DM dm, PetscInt p, PetscBool useCone, PetscBool useTransitiveClosure, PetscInt *adjSize, PetscInt *adj[])
209 {
210   static PetscInt asiz = 0;
211   PetscErrorCode  ierr;
212 
213   PetscFunctionBeginHot;
214   if (!*adj) {
215     PetscInt depth, maxConeSize, maxSupportSize;
216 
217     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
218     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
219     asiz = PetscPowInt(maxConeSize, depth+1) * PetscPowInt(maxSupportSize, depth+1) + 1;
220     ierr = PetscMalloc1(asiz,adj);CHKERRQ(ierr);
221   }
222   if (*adjSize < 0) *adjSize = asiz;
223   if (useTransitiveClosure) {
224     ierr = DMPlexGetAdjacency_Transitive_Internal(dm, p, useCone, adjSize, *adj);CHKERRQ(ierr);
225   } else if (useCone) {
226     ierr = DMPlexGetAdjacency_Cone_Internal(dm, p, adjSize, *adj);CHKERRQ(ierr);
227   } else {
228     ierr = DMPlexGetAdjacency_Support_Internal(dm, p, adjSize, *adj);CHKERRQ(ierr);
229   }
230   PetscFunctionReturn(0);
231 }
232 
233 #undef __FUNCT__
234 #define __FUNCT__ "DMPlexGetAdjacency"
235 /*@
236   DMPlexGetAdjacency - Return all points adjacent to the given point
237 
238   Input Parameters:
239 + dm - The DM object
240 . p  - The point
241 . adjSize - The maximum size of adj if it is non-NULL, or PETSC_DETERMINE
242 - adj - Either NULL so that the array is allocated, or an existing array with size adjSize
243 
244   Output Parameters:
245 + adjSize - The number of adjacent points
246 - adj - The adjacent points
247 
248   Level: advanced
249 
250   Notes: The user must PetscFree the adj array if it was not passed in.
251 
252 .seealso: DMPlexSetAdjacencyUseCone(), DMPlexSetAdjacencyUseClosure(), DMPlexDistribute(), DMCreateMatrix(), DMPlexPreallocateOperator()
253 @*/
254 PetscErrorCode DMPlexGetAdjacency(DM dm, PetscInt p, PetscInt *adjSize, PetscInt *adj[])
255 {
256   DM_Plex       *mesh = (DM_Plex *) dm->data;
257   PetscErrorCode ierr;
258 
259   PetscFunctionBeginHot;
260   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
261   PetscValidPointer(adjSize,3);
262   PetscValidPointer(adj,4);
263   ierr = DMPlexGetAdjacency_Internal(dm, p, mesh->useCone, mesh->useClosure, adjSize, adj);CHKERRQ(ierr);
264   PetscFunctionReturn(0);
265 }
266 
267 #undef __FUNCT__
268 #define __FUNCT__ "DMPlexDistributeField"
269 /*@
270   DMPlexDistributeField - Distribute field data to match a given PetscSF, usually the SF from mesh distribution
271 
272   Collective on DM
273 
274   Input Parameters:
275 + dm - The DMPlex object
276 . pointSF - The PetscSF describing the communication pattern
277 . originalSection - The PetscSection for existing data layout
278 - originalVec - The existing data
279 
280   Output Parameters:
281 + newSection - The PetscSF describing the new data layout
282 - newVec - The new data
283 
284   Level: developer
285 
286 .seealso: DMPlexDistribute(), DMPlexDistributeData()
287 @*/
288 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
289 {
290   PetscSF        fieldSF;
291   PetscInt      *remoteOffsets, fieldSize;
292   PetscScalar   *originalValues, *newValues;
293   PetscErrorCode ierr;
294 
295   PetscFunctionBegin;
296   ierr = PetscLogEventBegin(DMPLEX_DistributeField,dm,0,0,0);CHKERRQ(ierr);
297   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
298 
299   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
300   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
301   ierr = VecSetType(newVec,dm->vectype);CHKERRQ(ierr);
302 
303   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
304   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
305   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
306   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
307   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
308   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
309   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
310   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
311   ierr = PetscLogEventEnd(DMPLEX_DistributeField,dm,0,0,0);CHKERRQ(ierr);
312   PetscFunctionReturn(0);
313 }
314 
315 #undef __FUNCT__
316 #define __FUNCT__ "DMPlexDistributeData"
317 /*@
318   DMPlexDistributeData - Distribute field data to match a given PetscSF, usually the SF from mesh distribution
319 
320   Collective on DM
321 
322   Input Parameters:
323 + dm - The DMPlex object
324 . pointSF - The PetscSF describing the communication pattern
325 . originalSection - The PetscSection for existing data layout
326 . datatype - The type of data
327 - originalData - The existing data
328 
329   Output Parameters:
330 + newSection - The PetscSF describing the new data layout
331 - newData - The new data
332 
333   Level: developer
334 
335 .seealso: DMPlexDistribute(), DMPlexDistributeField()
336 @*/
337 PetscErrorCode DMPlexDistributeData(DM dm, PetscSF pointSF, PetscSection originalSection, MPI_Datatype datatype, void *originalData, PetscSection newSection, void **newData)
338 {
339   PetscSF        fieldSF;
340   PetscInt      *remoteOffsets, fieldSize;
341   PetscMPIInt    dataSize;
342   PetscErrorCode ierr;
343 
344   PetscFunctionBegin;
345   ierr = PetscLogEventBegin(DMPLEX_DistributeData,dm,0,0,0);CHKERRQ(ierr);
346   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
347 
348   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
349   ierr = MPI_Type_size(datatype, &dataSize);CHKERRQ(ierr);
350   ierr = PetscMalloc(fieldSize * dataSize, newData);CHKERRQ(ierr);
351 
352   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
353   ierr = PetscSFBcastBegin(fieldSF, datatype, originalData, *newData);CHKERRQ(ierr);
354   ierr = PetscSFBcastEnd(fieldSF, datatype, originalData, *newData);CHKERRQ(ierr);
355   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
356   ierr = PetscLogEventEnd(DMPLEX_DistributeData,dm,0,0,0);CHKERRQ(ierr);
357   PetscFunctionReturn(0);
358 }
359 
360 #undef __FUNCT__
361 #define __FUNCT__ "DMPlexDistribute"
362 /*@C
363   DMPlexDistribute - Distributes the mesh and any associated sections.
364 
365   Not Collective
366 
367   Input Parameter:
368 + dm  - The original DMPlex object
369 . partitioner - The partitioning package, or NULL for the default
370 - overlap - The overlap of partitions, 0 is the default
371 
372   Output Parameter:
373 + sf - The PetscSF used for point distribution
374 - parallelMesh - The distributed DMPlex object, or NULL
375 
376   Note: If the mesh was not distributed, the return value is NULL.
377 
378   The user can control the definition of adjacency for the mesh using DMPlexGetAdjacencyUseCone() and
379   DMPlexSetAdjacencyUseClosure(). They should choose the combination appropriate for the function
380   representation on the mesh.
381 
382   Level: intermediate
383 
384 .keywords: mesh, elements
385 .seealso: DMPlexCreate(), DMPlexDistributeByFace(), DMPlexSetAdjacencyUseCone(), DMPlexSetAdjacencyUseClosure()
386 @*/
387 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, PetscSF *sf, DM *dmParallel)
388 {
389   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
390   MPI_Comm               comm;
391   const PetscInt         height = 0;
392   PetscInt               dim, numRemoteRanks;
393   IS                     origCellPart,        origPart,        cellPart,        part;
394   PetscSection           origCellPartSection, origPartSection, cellPartSection, partSection;
395   PetscSFNode           *remoteRanks;
396   PetscSF                partSF, pointSF, coneSF;
397   ISLocalToGlobalMapping renumbering;
398   PetscSection           originalConeSection, newConeSection;
399   PetscInt              *remoteOffsets;
400   PetscInt              *cones, *newCones, newConesSize;
401   PetscBool              flg;
402   PetscMPIInt            rank, numProcs, p;
403   PetscErrorCode         ierr;
404 
405   PetscFunctionBegin;
406   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
407   if (sf) PetscValidPointer(sf,4);
408   PetscValidPointer(dmParallel,5);
409 
410   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
411   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
412   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
413   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
414 
415   *dmParallel = NULL;
416   if (numProcs == 1) PetscFunctionReturn(0);
417 
418   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
419   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
420   ierr = PetscLogEventBegin(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
421   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
422   ierr = DMPlexCreatePartition(dm, partitioner, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
423   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
424   if (!rank) numRemoteRanks = numProcs;
425   else       numRemoteRanks = 0;
426   ierr = PetscMalloc1(numRemoteRanks, &remoteRanks);CHKERRQ(ierr);
427   for (p = 0; p < numRemoteRanks; ++p) {
428     remoteRanks[p].rank  = p;
429     remoteRanks[p].index = 0;
430   }
431   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
432   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
433   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
434   if (flg) {
435     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
436     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
437     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
438     if (origCellPart) {
439       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
440       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
441       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
442     }
443     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
444   }
445   /* Close the partition over the mesh */
446   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
447   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
448   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
449   /* Create new mesh */
450   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
451   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
452   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
453   pmesh = (DM_Plex*) (*dmParallel)->data;
454   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
455   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
456   if (flg) {
457     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
458     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
459     ierr = ISView(part, NULL);CHKERRQ(ierr);
460     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
461     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
462     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
463   }
464   ierr = PetscLogEventEnd(DMPLEX_Partition,dm,0,0,0);CHKERRQ(ierr);
465   ierr = PetscLogEventBegin(DMPLEX_DistributeCones,dm,0,0,0);CHKERRQ(ierr);
466   /* Distribute cone section */
467   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
468   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
469   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
470   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
471   {
472     PetscInt pStart, pEnd, p;
473 
474     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
475     for (p = pStart; p < pEnd; ++p) {
476       PetscInt coneSize;
477       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
478       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
479     }
480   }
481   /* Communicate and renumber cones */
482   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
483   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
484   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
485   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
486   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
487   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
488   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
489   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
490   if (flg) {
491     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
492     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
493     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
494     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
495     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
496   }
497   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
498   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
499   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
500   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
501   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
502   ierr = PetscLogEventEnd(DMPLEX_DistributeCones,dm,0,0,0);CHKERRQ(ierr);
503   /* Create supports and stratify sieve */
504   {
505     PetscInt pStart, pEnd;
506 
507     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
508     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
509   }
510   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
511   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
512   /* Distribute Coordinates */
513   {
514     PetscSection originalCoordSection, newCoordSection;
515     Vec          originalCoordinates, newCoordinates;
516     const char  *name;
517 
518     ierr = DMGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
519     ierr = DMGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
520     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
521     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
522     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
523     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
524 
525     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
526     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
527     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
528   }
529   /* Distribute labels */
530   ierr = PetscLogEventBegin(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
531   {
532     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
533     PetscInt numLabels = 0, l;
534 
535     /* Bcast number of labels */
536     while (next) {++numLabels; next = next->next;}
537     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
538     next = mesh->labels;
539     for (l = 0; l < numLabels; ++l) {
540       DMLabel   labelNew;
541       PetscBool isdepth;
542 
543       /* Skip "depth" because it is recreated */
544       if (!rank) {ierr = PetscStrcmp(next->name, "depth", &isdepth);CHKERRQ(ierr);}
545       ierr = MPI_Bcast(&isdepth, 1, MPIU_BOOL, 0, comm);CHKERRQ(ierr);
546       if (isdepth) {if (!rank) next = next->next; continue;}
547       ierr = DMLabelDistribute(next, partSection, part, renumbering, &labelNew);CHKERRQ(ierr);
548       /* Insert into list */
549       if (newNext) newNext->next = labelNew;
550       else         pmesh->labels = labelNew;
551       newNext = labelNew;
552       if (!rank) next = next->next;
553     }
554   }
555   ierr = PetscLogEventEnd(DMPLEX_DistributeLabels,dm,0,0,0);CHKERRQ(ierr);
556   /* Setup hybrid structure */
557   {
558     const PetscInt *gpoints;
559     PetscInt        depth, n, d;
560 
561     for (d = 0; d <= dim; ++d) {pmesh->hybridPointMax[d] = mesh->hybridPointMax[d];}
562     ierr = MPI_Bcast(pmesh->hybridPointMax, dim+1, MPIU_INT, 0, comm);CHKERRQ(ierr);
563     ierr = ISLocalToGlobalMappingGetSize(renumbering, &n);CHKERRQ(ierr);
564     ierr = ISLocalToGlobalMappingGetIndices(renumbering, &gpoints);CHKERRQ(ierr);
565     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
566     for (d = 0; d <= dim; ++d) {
567       PetscInt pmax = pmesh->hybridPointMax[d], newmax = 0, pEnd, stratum[2], p;
568 
569       if (pmax < 0) continue;
570       ierr = DMPlexGetDepthStratum(dm, d > depth ? depth : d, &stratum[0], &stratum[1]);CHKERRQ(ierr);
571       ierr = DMPlexGetDepthStratum(*dmParallel, d, NULL, &pEnd);CHKERRQ(ierr);
572       ierr = MPI_Bcast(stratum, 2, MPIU_INT, 0, comm);CHKERRQ(ierr);
573       for (p = 0; p < n; ++p) {
574         const PetscInt point = gpoints[p];
575 
576         if ((point >= stratum[0]) && (point < stratum[1]) && (point >= pmax)) ++newmax;
577       }
578       if (newmax > 0) pmesh->hybridPointMax[d] = pEnd - newmax;
579       else            pmesh->hybridPointMax[d] = -1;
580     }
581     ierr = ISLocalToGlobalMappingRestoreIndices(renumbering, &gpoints);CHKERRQ(ierr);
582   }
583   /* Cleanup Partition */
584   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
585   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
586   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
587   ierr = ISDestroy(&part);CHKERRQ(ierr);
588   /* Create point SF for parallel mesh */
589   ierr = PetscLogEventBegin(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
590   {
591     const PetscInt *leaves;
592     PetscSFNode    *remotePoints, *rowners, *lowners;
593     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
594     PetscInt        pStart, pEnd;
595 
596     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
597     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
598     ierr = PetscMalloc2(numRoots,&rowners,numLeaves,&lowners);CHKERRQ(ierr);
599     for (p=0; p<numRoots; p++) {
600       rowners[p].rank  = -1;
601       rowners[p].index = -1;
602     }
603     if (origCellPart) {
604       /* Make sure points in the original partition are not assigned to other procs */
605       const PetscInt *origPoints;
606 
607       ierr = DMPlexCreatePartitionClosure(dm, origCellPartSection, origCellPart, &origPartSection, &origPart);CHKERRQ(ierr);
608       ierr = ISGetIndices(origPart, &origPoints);CHKERRQ(ierr);
609       for (p = 0; p < numProcs; ++p) {
610         PetscInt dof, off, d;
611 
612         ierr = PetscSectionGetDof(origPartSection, p, &dof);CHKERRQ(ierr);
613         ierr = PetscSectionGetOffset(origPartSection, p, &off);CHKERRQ(ierr);
614         for (d = off; d < off+dof; ++d) {
615           rowners[origPoints[d]].rank = p;
616         }
617       }
618       ierr = ISRestoreIndices(origPart, &origPoints);CHKERRQ(ierr);
619       ierr = ISDestroy(&origPart);CHKERRQ(ierr);
620       ierr = PetscSectionDestroy(&origPartSection);CHKERRQ(ierr);
621     }
622     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
623     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
624 
625     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
626     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
627     for (p = 0; p < numLeaves; ++p) {
628       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
629         lowners[p].rank  = rank;
630         lowners[p].index = leaves ? leaves[p] : p;
631       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
632         lowners[p].rank  = -2;
633         lowners[p].index = -2;
634       }
635     }
636     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
637       rowners[p].rank  = -3;
638       rowners[p].index = -3;
639     }
640     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
641     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
642     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
643     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
644     for (p = 0; p < numLeaves; ++p) {
645       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
646       if (lowners[p].rank != rank) ++numGhostPoints;
647     }
648     ierr = PetscMalloc1(numGhostPoints,    &ghostPoints);CHKERRQ(ierr);
649     ierr = PetscMalloc1(numGhostPoints, &remotePoints);CHKERRQ(ierr);
650     for (p = 0, gp = 0; p < numLeaves; ++p) {
651       if (lowners[p].rank != rank) {
652         ghostPoints[gp]        = leaves ? leaves[p] : p;
653         remotePoints[gp].rank  = lowners[p].rank;
654         remotePoints[gp].index = lowners[p].index;
655         ++gp;
656       }
657     }
658     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
659     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
660     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
661   }
662   pmesh->useCone    = mesh->useCone;
663   pmesh->useClosure = mesh->useClosure;
664   ierr = PetscLogEventEnd(DMPLEX_DistributeSF,dm,0,0,0);CHKERRQ(ierr);
665   /* Cleanup */
666   if (sf) {*sf = pointSF;}
667   else    {ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);}
668   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
669   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
670   PetscFunctionReturn(0);
671 }
672