xref: /petsc/src/dm/impls/plex/plex.c (revision 0f453b9297fe252606e7a346af3b68a47f9eb3be)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/isimpl.h>
4 
5 /* Logging support */
6 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
7 
8 PETSC_EXTERN PetscErrorCode VecView_Seq(Vec, PetscViewer);
9 PETSC_EXTERN PetscErrorCode VecView_MPI(Vec, PetscViewer);
10 
11 #undef __FUNCT__
12 #define __FUNCT__ "VecView_Plex_Local"
13 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
14 {
15   DM             dm;
16   PetscBool      isvtk;
17   PetscErrorCode ierr;
18 
19   PetscFunctionBegin;
20   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
21   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
22   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
23   if (isvtk) {
24     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
25     PetscSection            section;
26     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
27 
28     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
29     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, NULL);CHKERRQ(ierr);
32     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, NULL);CHKERRQ(ierr);
33     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
34     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
35     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
36     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
37     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
38     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
39       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
40     } else if (cdof && vdof) {
41       SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
42     } else if (cdof) {
43       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
44        * vector or just happens to have the same number of dofs as the dimension. */
45       if (cdof == dim) {
46         ft = PETSC_VTK_CELL_VECTOR_FIELD;
47       } else {
48         ft = PETSC_VTK_CELL_FIELD;
49       }
50     } else if (vdof) {
51       if (vdof == dim) {
52         ft = PETSC_VTK_POINT_VECTOR_FIELD;
53       } else {
54         ft = PETSC_VTK_POINT_FIELD;
55       }
56     } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
57 
58     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
59     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
60     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
61   } else {
62     PetscBool isseq;
63 
64     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
65     if (isseq) {
66       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
67     } else {
68       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
69     }
70   }
71   PetscFunctionReturn(0);
72 }
73 
74 #undef __FUNCT__
75 #define __FUNCT__ "VecView_Plex"
76 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
77 {
78   DM             dm;
79   PetscBool      isvtk;
80   PetscErrorCode ierr;
81 
82   PetscFunctionBegin;
83   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
84   if (!dm) SETERRQ(PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
85   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
86   if (isvtk) {
87     Vec         locv;
88     const char *name;
89 
90     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
91     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
92     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
95     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
96     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
97   } else {
98     PetscBool isseq;
99 
100     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
101     if (isseq) {
102       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
103     } else {
104       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
105     }
106   }
107   PetscFunctionReturn(0);
108 }
109 
110 #undef __FUNCT__
111 #define __FUNCT__ "DMPlexView_Ascii"
112 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
113 {
114   DM_Plex          *mesh = (DM_Plex*) dm->data;
115   DM                cdm;
116   DMLabel           markers;
117   PetscSection      coordSection;
118   Vec               coordinates;
119   PetscViewerFormat format;
120   PetscErrorCode    ierr;
121 
122   PetscFunctionBegin;
123   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
124   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
125   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
126   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
127   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
128     const char *name;
129     PetscInt    maxConeSize, maxSupportSize;
130     PetscInt    pStart, pEnd, p;
131     PetscMPIInt rank, size;
132 
133     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
134     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
135     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
136     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
137     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
138     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
139     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
140     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
142     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
143     for (p = pStart; p < pEnd; ++p) {
144       PetscInt dof, off, s;
145 
146       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
147       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
148       for (s = off; s < off+dof; ++s) {
149         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
150       }
151     }
152     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
153     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
154     for (p = pStart; p < pEnd; ++p) {
155       PetscInt dof, off, c;
156 
157       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
158       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
159       for (c = off; c < off+dof; ++c) {
160         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
161       }
162     }
163     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
164     ierr = PetscSectionGetChart(coordSection, &pStart, NULL);CHKERRQ(ierr);
165     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
166     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
167     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
168     if (size > 1) {
169       PetscSF sf;
170 
171       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
172       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
173     }
174     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
175   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
176     const char  *name;
177     const char  *colors[3] = {"red", "blue", "green"};
178     const int    numColors  = 3;
179     PetscReal    scale      = 2.0;
180     PetscScalar *coords;
181     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
182     PetscMPIInt  rank, size;
183 
184     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
185     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
186     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
187     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
188     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
189     ierr = PetscViewerASCIIPrintf(viewer, "\
190 \\documentclass[crop,multi=false]{standalone}\n\n\
191 \\usepackage{tikz}\n\
192 \\usepackage{pgflibraryshapes}\n\
193 \\usetikzlibrary{backgrounds}\n\
194 \\usetikzlibrary{arrows}\n\
195 \\begin{document}\n\
196 \\section{%s}\n\
197 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
198     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
199     for (p = 0; p < size; ++p) {
200       if (p > 0 && p == size-1) {
201         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
202       } else if (p > 0) {
203         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
204       }
205       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
206     }
207     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
208 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
209     /* Plot vertices */
210     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
211     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
212     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
213     for (v = vStart; v < vEnd; ++v) {
214       PetscInt off, dof, d;
215 
216       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
217       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
218       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
219       for (d = 0; d < dof; ++d) {
220         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
221         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
222       }
223       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
224     }
225     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
226     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
227     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
228     /* Plot edges */
229     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
230     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
231     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
232     for (e = eStart; e < eEnd; ++e) {
233       const PetscInt *cone;
234       PetscInt        coneSize, offA, offB, dof, d;
235 
236       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
237       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
238       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
239       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
240       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
242       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
243       for (d = 0; d < dof; ++d) {
244         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
245         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
246       }
247       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
248     }
249     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
250     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
251     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
252     /* Plot cells */
253     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
254     for (c = cStart; c < cEnd; ++c) {
255       PetscInt *closure = NULL;
256       PetscInt  closureSize, firstPoint = -1;
257 
258       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
259       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
260       for (p = 0; p < closureSize*2; p += 2) {
261         const PetscInt point = closure[p];
262 
263         if ((point < vStart) || (point >= vEnd)) continue;
264         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
265         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
266         if (firstPoint < 0) firstPoint = point;
267       }
268       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
269       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
270       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
271     }
272     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
273     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
275   } else {
276     MPI_Comm    comm;
277     PetscInt   *sizes;
278     PetscInt    locDepth, depth, dim, d;
279     PetscInt    pStart, pEnd, p;
280     PetscInt    numLabels, l;
281     PetscMPIInt size;
282 
283     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
284     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
285     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
286     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
287     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
288     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
289     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
290     if (depth == 1) {
291       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
292       pEnd = pEnd - pStart;
293       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
294       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
295       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
296       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
297       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
298       pEnd = pEnd - pStart;
299       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
300       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
301       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
302       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
303     } else {
304       for (d = 0; d <= dim; d++) {
305         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
306         pEnd = pEnd - pStart;
307         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
308         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
309         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
310         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
311       }
312     }
313     ierr = PetscFree(sizes);CHKERRQ(ierr);
314     ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
315     if (numLabels) {ierr = PetscViewerASCIIPrintf(viewer, "Labels:\n");CHKERRQ(ierr);}
316     for (l = 0; l < numLabels; ++l) {
317       DMLabel         label;
318       const char     *name;
319       IS              valueIS;
320       const PetscInt *values;
321       PetscInt        numValues, v;
322 
323       ierr = DMPlexGetLabelName(dm, l, &name);CHKERRQ(ierr);
324       ierr = DMPlexGetLabel(dm, name, &label);CHKERRQ(ierr);
325       ierr = DMLabelGetNumValues(label, &numValues);CHKERRQ(ierr);
326       ierr = PetscViewerASCIIPrintf(viewer, "  %s: %d strata of sizes (", name, numValues);CHKERRQ(ierr);
327       ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
328       ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
329       for (v = 0; v < numValues; ++v) {
330         PetscInt size;
331 
332         ierr = DMLabelGetStratumSize(label, values[v], &size);CHKERRQ(ierr);
333         if (v > 0) {ierr = PetscViewerASCIIPrintf(viewer, ", ");CHKERRQ(ierr);}
334         ierr = PetscViewerASCIIPrintf(viewer, "%d", size);CHKERRQ(ierr);
335       }
336       ierr = PetscViewerASCIIPrintf(viewer, ")\n");CHKERRQ(ierr);
337       ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
338       ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
339     }
340   }
341   PetscFunctionReturn(0);
342 }
343 
344 #undef __FUNCT__
345 #define __FUNCT__ "DMView_Plex"
346 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
347 {
348   PetscBool      iascii, isbinary;
349   PetscErrorCode ierr;
350 
351   PetscFunctionBegin;
352   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
353   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
354   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
355   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
356   if (iascii) {
357     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
358 #if 0
359   } else if (isbinary) {
360     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
361 #endif
362   }
363   PetscFunctionReturn(0);
364 }
365 
366 #undef __FUNCT__
367 #define __FUNCT__ "DMDestroy_Plex"
368 PetscErrorCode DMDestroy_Plex(DM dm)
369 {
370   DM_Plex       *mesh = (DM_Plex*) dm->data;
371   DMLabel        next  = mesh->labels;
372   PetscErrorCode ierr;
373 
374   PetscFunctionBegin;
375   if (--mesh->refct > 0) PetscFunctionReturn(0);
376   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
377   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
378   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
379   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
380   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
381   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
382   while (next) {
383     DMLabel tmp = next->next;
384 
385     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
386     next = tmp;
387   }
388   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
389   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
390   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
391   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
392   ierr = PetscFree(mesh);CHKERRQ(ierr);
393   PetscFunctionReturn(0);
394 }
395 
396 #undef __FUNCT__
397 #define __FUNCT__ "DMCreateMatrix_Plex"
398 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
399 {
400   PetscSection   section, sectionGlobal;
401   PetscInt       bs = -1;
402   PetscInt       localSize;
403   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
404   PetscErrorCode ierr;
405 
406   PetscFunctionBegin;
407 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
408   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
409 #endif
410   if (!mtype) mtype = MATAIJ;
411   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
412   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
413   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
414   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
415   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
416   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
417   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
418   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
419   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
420   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
421   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
422   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
423   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
424   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
425   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
426   /* Check for symmetric storage */
427   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
428   if (isSymmetric) {
429     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
430   }
431   if (!isShell) {
432     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
433     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
434 
435     if (bs < 0) {
436       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
437         PetscInt pStart, pEnd, p, dof, cdof;
438 
439         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
440         for (p = pStart; p < pEnd; ++p) {
441           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
442           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
443           if (dof-cdof) {
444             if (bs < 0) {
445               bs = dof-cdof;
446             } else if (bs != dof-cdof) {
447               /* Layout does not admit a pointwise block size */
448               bs = 1;
449               break;
450             }
451           }
452         }
453         /* Must have same blocksize on all procs (some might have no points) */
454         bsLocal = bs;
455         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
456         bsLocal = bs < 0 ? bsMax : bs;
457         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
458         if (bsMin != bsMax) {
459           bs = 1;
460         } else {
461           bs = bsMax;
462         }
463       } else {
464         bs = 1;
465       }
466     }
467     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
468     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
469     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
470     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
471     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
472     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
473     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
474   }
475   PetscFunctionReturn(0);
476 }
477 
478 #undef __FUNCT__
479 #define __FUNCT__ "DMPlexGetDimension"
480 /*@
481   DMPlexGetDimension - Return the topological mesh dimension
482 
483   Not collective
484 
485   Input Parameter:
486 . mesh - The DMPlex
487 
488   Output Parameter:
489 . dim - The topological mesh dimension
490 
491   Level: beginner
492 
493 .seealso: DMPlexCreate()
494 @*/
495 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
496 {
497   DM_Plex *mesh = (DM_Plex*) dm->data;
498 
499   PetscFunctionBegin;
500   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
501   PetscValidPointer(dim, 2);
502   *dim = mesh->dim;
503   PetscFunctionReturn(0);
504 }
505 
506 #undef __FUNCT__
507 #define __FUNCT__ "DMPlexSetDimension"
508 /*@
509   DMPlexSetDimension - Set the topological mesh dimension
510 
511   Collective on mesh
512 
513   Input Parameters:
514 + mesh - The DMPlex
515 - dim - The topological mesh dimension
516 
517   Level: beginner
518 
519 .seealso: DMPlexCreate()
520 @*/
521 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
522 {
523   DM_Plex *mesh = (DM_Plex*) dm->data;
524 
525   PetscFunctionBegin;
526   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
527   PetscValidLogicalCollectiveInt(dm, dim, 2);
528   mesh->dim               = dim;
529   mesh->preallocCenterDim = dim;
530   PetscFunctionReturn(0);
531 }
532 
533 #undef __FUNCT__
534 #define __FUNCT__ "DMPlexGetChart"
535 /*@
536   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
537 
538   Not collective
539 
540   Input Parameter:
541 . mesh - The DMPlex
542 
543   Output Parameters:
544 + pStart - The first mesh point
545 - pEnd   - The upper bound for mesh points
546 
547   Level: beginner
548 
549 .seealso: DMPlexCreate(), DMPlexSetChart()
550 @*/
551 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
552 {
553   DM_Plex       *mesh = (DM_Plex*) dm->data;
554   PetscErrorCode ierr;
555 
556   PetscFunctionBegin;
557   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
558   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
559   PetscFunctionReturn(0);
560 }
561 
562 #undef __FUNCT__
563 #define __FUNCT__ "DMPlexSetChart"
564 /*@
565   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
566 
567   Not collective
568 
569   Input Parameters:
570 + mesh - The DMPlex
571 . pStart - The first mesh point
572 - pEnd   - The upper bound for mesh points
573 
574   Output Parameters:
575 
576   Level: beginner
577 
578 .seealso: DMPlexCreate(), DMPlexGetChart()
579 @*/
580 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
581 {
582   DM_Plex       *mesh = (DM_Plex*) dm->data;
583   PetscErrorCode ierr;
584 
585   PetscFunctionBegin;
586   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
587   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
588   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
589   PetscFunctionReturn(0);
590 }
591 
592 #undef __FUNCT__
593 #define __FUNCT__ "DMPlexGetConeSize"
594 /*@
595   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
596 
597   Not collective
598 
599   Input Parameters:
600 + mesh - The DMPlex
601 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
602 
603   Output Parameter:
604 . size - The cone size for point p
605 
606   Level: beginner
607 
608 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
609 @*/
610 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
611 {
612   DM_Plex       *mesh = (DM_Plex*) dm->data;
613   PetscErrorCode ierr;
614 
615   PetscFunctionBegin;
616   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
617   PetscValidPointer(size, 3);
618   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
619   PetscFunctionReturn(0);
620 }
621 
622 #undef __FUNCT__
623 #define __FUNCT__ "DMPlexSetConeSize"
624 /*@
625   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
626 
627   Not collective
628 
629   Input Parameters:
630 + mesh - The DMPlex
631 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
632 - size - The cone size for point p
633 
634   Output Parameter:
635 
636   Note:
637   This should be called after DMPlexSetChart().
638 
639   Level: beginner
640 
641 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
642 @*/
643 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
644 {
645   DM_Plex       *mesh = (DM_Plex*) dm->data;
646   PetscErrorCode ierr;
647 
648   PetscFunctionBegin;
649   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
650   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
651 
652   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
653   PetscFunctionReturn(0);
654 }
655 
656 #undef __FUNCT__
657 #define __FUNCT__ "DMPlexGetCone"
658 /*@C
659   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
660 
661   Not collective
662 
663   Input Parameters:
664 + mesh - The DMPlex
665 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
666 
667   Output Parameter:
668 . cone - An array of points which are on the in-edges for point p
669 
670   Level: beginner
671 
672   Fortran Notes:
673   Since it returns an array, this routine is only available in Fortran 90, and you must
674   include petsc.h90 in your code.
675 
676   You must also call DMPlexRestoreCone() after you finish using the returned array.
677 
678 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
679 @*/
680 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
681 {
682   DM_Plex       *mesh = (DM_Plex*) dm->data;
683   PetscInt       off;
684   PetscErrorCode ierr;
685 
686   PetscFunctionBegin;
687   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
688   PetscValidPointer(cone, 3);
689   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
690   *cone = &mesh->cones[off];
691   PetscFunctionReturn(0);
692 }
693 
694 #undef __FUNCT__
695 #define __FUNCT__ "DMPlexSetCone"
696 /*@
697   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
698 
699   Not collective
700 
701   Input Parameters:
702 + mesh - The DMPlex
703 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
704 - cone - An array of points which are on the in-edges for point p
705 
706   Output Parameter:
707 
708   Note:
709   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
710 
711   Level: beginner
712 
713 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
714 @*/
715 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
716 {
717   DM_Plex       *mesh = (DM_Plex*) dm->data;
718   PetscInt       pStart, pEnd;
719   PetscInt       dof, off, c;
720   PetscErrorCode ierr;
721 
722   PetscFunctionBegin;
723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
724   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
725   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
726   if (dof) PetscValidPointer(cone, 3);
727   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
728   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
729   for (c = 0; c < dof; ++c) {
730     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
731     mesh->cones[off+c] = cone[c];
732   }
733   PetscFunctionReturn(0);
734 }
735 
736 #undef __FUNCT__
737 #define __FUNCT__ "DMPlexGetConeOrientation"
738 /*@C
739   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
740 
741   Not collective
742 
743   Input Parameters:
744 + mesh - The DMPlex
745 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
746 
747   Output Parameter:
748 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
749                     integer giving the prescription for cone traversal. If it is negative, the cone is
750                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
751                     the index of the cone point on which to start.
752 
753   Level: beginner
754 
755   Fortran Notes:
756   Since it returns an array, this routine is only available in Fortran 90, and you must
757   include petsc.h90 in your code.
758 
759   You must also call DMPlexRestoreConeOrientation() after you finish using the returned array.
760 
761 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
762 @*/
763 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
764 {
765   DM_Plex       *mesh = (DM_Plex*) dm->data;
766   PetscInt       off;
767   PetscErrorCode ierr;
768 
769   PetscFunctionBegin;
770   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
771 #if defined(PETSC_USE_DEBUG)
772   {
773     PetscInt dof;
774     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
775     if (dof) PetscValidPointer(coneOrientation, 3);
776   }
777 #endif
778   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
779 
780   *coneOrientation = &mesh->coneOrientations[off];
781   PetscFunctionReturn(0);
782 }
783 
784 #undef __FUNCT__
785 #define __FUNCT__ "DMPlexSetConeOrientation"
786 /*@
787   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
788 
789   Not collective
790 
791   Input Parameters:
792 + mesh - The DMPlex
793 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
794 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
795                     integer giving the prescription for cone traversal. If it is negative, the cone is
796                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
797                     the index of the cone point on which to start.
798 
799   Output Parameter:
800 
801   Note:
802   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
803 
804   Level: beginner
805 
806 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
807 @*/
808 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
809 {
810   DM_Plex       *mesh = (DM_Plex*) dm->data;
811   PetscInt       pStart, pEnd;
812   PetscInt       dof, off, c;
813   PetscErrorCode ierr;
814 
815   PetscFunctionBegin;
816   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
817   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
818   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
819   if (dof) PetscValidPointer(coneOrientation, 3);
820   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
821   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
822   for (c = 0; c < dof; ++c) {
823     PetscInt cdof, o = coneOrientation[c];
824 
825     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
826     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
827     mesh->coneOrientations[off+c] = o;
828   }
829   PetscFunctionReturn(0);
830 }
831 
832 #undef __FUNCT__
833 #define __FUNCT__ "DMPlexInsertCone"
834 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
835 {
836   DM_Plex       *mesh = (DM_Plex*) dm->data;
837   PetscInt       pStart, pEnd;
838   PetscInt       dof, off;
839   PetscErrorCode ierr;
840 
841   PetscFunctionBegin;
842   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
843   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
844   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
845   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
846   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
847   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
848   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
849   mesh->cones[off+conePos] = conePoint;
850   PetscFunctionReturn(0);
851 }
852 
853 #undef __FUNCT__
854 #define __FUNCT__ "DMPlexInsertConeOrientation"
855 PetscErrorCode DMPlexInsertConeOrientation(DM dm, PetscInt p, PetscInt conePos, PetscInt coneOrientation)
856 {
857   DM_Plex       *mesh = (DM_Plex*) dm->data;
858   PetscInt       pStart, pEnd;
859   PetscInt       dof, off;
860   PetscErrorCode ierr;
861 
862   PetscFunctionBegin;
863   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
864   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
865   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
866   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
867   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
868   if ((conePos < 0) || (conePos >= dof)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
869   mesh->coneOrientations[off+conePos] = coneOrientation;
870   PetscFunctionReturn(0);
871 }
872 
873 #undef __FUNCT__
874 #define __FUNCT__ "DMPlexGetSupportSize"
875 /*@
876   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
877 
878   Not collective
879 
880   Input Parameters:
881 + mesh - The DMPlex
882 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
883 
884   Output Parameter:
885 . size - The support size for point p
886 
887   Level: beginner
888 
889 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
890 @*/
891 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
892 {
893   DM_Plex       *mesh = (DM_Plex*) dm->data;
894   PetscErrorCode ierr;
895 
896   PetscFunctionBegin;
897   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
898   PetscValidPointer(size, 3);
899   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
900   PetscFunctionReturn(0);
901 }
902 
903 #undef __FUNCT__
904 #define __FUNCT__ "DMPlexSetSupportSize"
905 /*@
906   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
907 
908   Not collective
909 
910   Input Parameters:
911 + mesh - The DMPlex
912 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
913 - size - The support size for point p
914 
915   Output Parameter:
916 
917   Note:
918   This should be called after DMPlexSetChart().
919 
920   Level: beginner
921 
922 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
923 @*/
924 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
925 {
926   DM_Plex       *mesh = (DM_Plex*) dm->data;
927   PetscErrorCode ierr;
928 
929   PetscFunctionBegin;
930   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
931   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
932 
933   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
934   PetscFunctionReturn(0);
935 }
936 
937 #undef __FUNCT__
938 #define __FUNCT__ "DMPlexGetSupport"
939 /*@C
940   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
941 
942   Not collective
943 
944   Input Parameters:
945 + mesh - The DMPlex
946 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
947 
948   Output Parameter:
949 . support - An array of points which are on the out-edges for point p
950 
951   Level: beginner
952 
953   Fortran Notes:
954   Since it returns an array, this routine is only available in Fortran 90, and you must
955   include petsc.h90 in your code.
956 
957   You must also call DMPlexRestoreSupport() after you finish using the returned array.
958 
959 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
960 @*/
961 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
962 {
963   DM_Plex       *mesh = (DM_Plex*) dm->data;
964   PetscInt       off;
965   PetscErrorCode ierr;
966 
967   PetscFunctionBegin;
968   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
969   PetscValidPointer(support, 3);
970   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
971   *support = &mesh->supports[off];
972   PetscFunctionReturn(0);
973 }
974 
975 #undef __FUNCT__
976 #define __FUNCT__ "DMPlexSetSupport"
977 /*@
978   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
979 
980   Not collective
981 
982   Input Parameters:
983 + mesh - The DMPlex
984 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
985 - support - An array of points which are on the in-edges for point p
986 
987   Output Parameter:
988 
989   Note:
990   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
991 
992   Level: beginner
993 
994 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
995 @*/
996 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
997 {
998   DM_Plex       *mesh = (DM_Plex*) dm->data;
999   PetscInt       pStart, pEnd;
1000   PetscInt       dof, off, c;
1001   PetscErrorCode ierr;
1002 
1003   PetscFunctionBegin;
1004   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1005   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1006   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1007   if (dof) PetscValidPointer(support, 3);
1008   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1009   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1010   for (c = 0; c < dof; ++c) {
1011     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1012     mesh->supports[off+c] = support[c];
1013   }
1014   PetscFunctionReturn(0);
1015 }
1016 
1017 #undef __FUNCT__
1018 #define __FUNCT__ "DMPlexInsertSupport"
1019 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1020 {
1021   DM_Plex       *mesh = (DM_Plex*) dm->data;
1022   PetscInt       pStart, pEnd;
1023   PetscInt       dof, off;
1024   PetscErrorCode ierr;
1025 
1026   PetscFunctionBegin;
1027   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1028   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1029   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1030   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1031   if ((p < pStart) || (p >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1032   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1033   if (supportPos >= dof) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1034   mesh->supports[off+supportPos] = supportPoint;
1035   PetscFunctionReturn(0);
1036 }
1037 
1038 #undef __FUNCT__
1039 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1040 /*@C
1041   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1042 
1043   Not collective
1044 
1045   Input Parameters:
1046 + mesh - The DMPlex
1047 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1048 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1049 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1050 
1051   Output Parameters:
1052 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1053 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1054 
1055   Note:
1056   If using internal storage (points is NULL on input), each call overwrites the last output.
1057 
1058   Fortran Notes:
1059   Since it returns an array, this routine is only available in Fortran 90, and you must
1060   include petsc.h90 in your code.
1061 
1062   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1063 
1064   Level: beginner
1065 
1066 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1067 @*/
1068 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1069 {
1070   DM_Plex        *mesh = (DM_Plex*) dm->data;
1071   PetscInt       *closure, *fifo;
1072   const PetscInt *tmp = NULL, *tmpO = NULL;
1073   PetscInt        tmpSize, t;
1074   PetscInt        depth       = 0, maxSize;
1075   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1076   PetscErrorCode  ierr;
1077 
1078   PetscFunctionBegin;
1079   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1080   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1081   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1082   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1083   if (*points) {
1084     closure = *points;
1085   } else {
1086     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1087   }
1088   closure[0] = p; closure[1] = 0;
1089   /* This is only 1-level */
1090   if (useCone) {
1091     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1092     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1093     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1094   } else {
1095     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1096     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1097   }
1098   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1099     const PetscInt cp = tmp[t];
1100     const PetscInt co = tmpO ? tmpO[t] : 0;
1101 
1102     closure[closureSize]   = cp;
1103     closure[closureSize+1] = co;
1104     fifo[fifoSize]         = cp;
1105     fifo[fifoSize+1]       = co;
1106   }
1107   while (fifoSize - fifoStart) {
1108     const PetscInt q   = fifo[fifoStart];
1109     const PetscInt o   = fifo[fifoStart+1];
1110     const PetscInt rev = o >= 0 ? 0 : 1;
1111     const PetscInt off = rev ? -(o+1) : o;
1112 
1113     if (useCone) {
1114       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1115       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1116       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1117     } else {
1118       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1119       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1120       tmpO = NULL;
1121     }
1122     for (t = 0; t < tmpSize; ++t) {
1123       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1124       const PetscInt cp = tmp[i];
1125       /* Must propogate orientation */
1126       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1127       PetscInt       c;
1128 
1129       /* Check for duplicate */
1130       for (c = 0; c < closureSize; c += 2) {
1131         if (closure[c] == cp) break;
1132       }
1133       if (c == closureSize) {
1134         closure[closureSize]   = cp;
1135         closure[closureSize+1] = co;
1136         fifo[fifoSize]         = cp;
1137         fifo[fifoSize+1]       = co;
1138         closureSize           += 2;
1139         fifoSize              += 2;
1140       }
1141     }
1142     fifoStart += 2;
1143   }
1144   if (numPoints) *numPoints = closureSize/2;
1145   if (points)    *points    = closure;
1146   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1147   PetscFunctionReturn(0);
1148 }
1149 
1150 #undef __FUNCT__
1151 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1152 /*@C
1153   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1154 
1155   Not collective
1156 
1157   Input Parameters:
1158 + mesh - The DMPlex
1159 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1160 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1161 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1162 
1163   Output Parameters:
1164 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1165 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1166 
1167   Note:
1168   If not using internal storage (points is not NULL on input), this call is unnecessary
1169 
1170   Fortran Notes:
1171   Since it returns an array, this routine is only available in Fortran 90, and you must
1172   include petsc.h90 in your code.
1173 
1174   The numPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1175 
1176   Level: beginner
1177 
1178 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1179 @*/
1180 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1181 {
1182   PetscErrorCode ierr;
1183 
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1186   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1187   PetscFunctionReturn(0);
1188 }
1189 
1190 #undef __FUNCT__
1191 #define __FUNCT__ "DMPlexGetMaxSizes"
1192 /*@
1193   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1194 
1195   Not collective
1196 
1197   Input Parameter:
1198 . mesh - The DMPlex
1199 
1200   Output Parameters:
1201 + maxConeSize - The maximum number of in-edges
1202 - maxSupportSize - The maximum number of out-edges
1203 
1204   Level: beginner
1205 
1206 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1207 @*/
1208 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1209 {
1210   DM_Plex *mesh = (DM_Plex*) dm->data;
1211 
1212   PetscFunctionBegin;
1213   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1214   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1215   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1216   PetscFunctionReturn(0);
1217 }
1218 
1219 #undef __FUNCT__
1220 #define __FUNCT__ "DMSetUp_Plex"
1221 PetscErrorCode DMSetUp_Plex(DM dm)
1222 {
1223   DM_Plex       *mesh = (DM_Plex*) dm->data;
1224   PetscInt       size;
1225   PetscErrorCode ierr;
1226 
1227   PetscFunctionBegin;
1228   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1229   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1230   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1231   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1232   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1233   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1234   if (mesh->maxSupportSize) {
1235     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1236     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1237     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1238   }
1239   PetscFunctionReturn(0);
1240 }
1241 
1242 #undef __FUNCT__
1243 #define __FUNCT__ "DMCreateSubDM_Plex"
1244 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1245 {
1246   PetscSection   section, sectionGlobal;
1247   PetscInt      *subIndices;
1248   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1249   PetscErrorCode ierr;
1250 
1251   PetscFunctionBegin;
1252   if (!numFields) PetscFunctionReturn(0);
1253   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1254   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1255   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1256   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1257   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1258   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1259   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1260   for (p = pStart; p < pEnd; ++p) {
1261     PetscInt gdof;
1262 
1263     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1264     if (gdof > 0) {
1265       for (f = 0; f < numFields; ++f) {
1266         PetscInt fdof, fcdof;
1267 
1268         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1269         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1270         subSize += fdof-fcdof;
1271       }
1272     }
1273   }
1274   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1275   for (p = pStart; p < pEnd; ++p) {
1276     PetscInt gdof, goff;
1277 
1278     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1279     if (gdof > 0) {
1280       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1281       for (f = 0; f < numFields; ++f) {
1282         PetscInt fdof, fcdof, fc, f2, poff = 0;
1283 
1284         /* Can get rid of this loop by storing field information in the global section */
1285         for (f2 = 0; f2 < fields[f]; ++f2) {
1286           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1287           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1288           poff += fdof-fcdof;
1289         }
1290         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1291         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1292         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1293           subIndices[subOff] = goff+poff+fc;
1294         }
1295       }
1296     }
1297   }
1298   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1299   if (subdm) {
1300     PetscSection subsection;
1301     PetscBool    haveNull = PETSC_FALSE;
1302     PetscInt     f, nf = 0;
1303 
1304     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1305     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1306     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1307     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1308     for (f = 0; f < numFields; ++f) {
1309       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1310       if ((*subdm)->nullspaceConstructors[f]) {
1311         haveNull = PETSC_TRUE;
1312         nf       = f;
1313       }
1314     }
1315     if (haveNull) {
1316       MatNullSpace nullSpace;
1317 
1318       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1319       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1320       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1321     }
1322     if (dm->fields) {
1323       if (nF != dm->numFields) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1324       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1325       for (f = 0; f < numFields; ++f) {
1326         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1327       }
1328       if (numFields == 1) {
1329         MatNullSpace space;
1330         Mat          pmat;
1331 
1332         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1333         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1334         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1335         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1336         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1337         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1338       }
1339     }
1340   }
1341   PetscFunctionReturn(0);
1342 }
1343 
1344 #undef __FUNCT__
1345 #define __FUNCT__ "DMPlexSymmetrize"
1346 /*@
1347   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1348 
1349   Not collective
1350 
1351   Input Parameter:
1352 . mesh - The DMPlex
1353 
1354   Output Parameter:
1355 
1356   Note:
1357   This should be called after all calls to DMPlexSetCone()
1358 
1359   Level: beginner
1360 
1361 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1362 @*/
1363 PetscErrorCode DMPlexSymmetrize(DM dm)
1364 {
1365   DM_Plex       *mesh = (DM_Plex*) dm->data;
1366   PetscInt      *offsets;
1367   PetscInt       supportSize;
1368   PetscInt       pStart, pEnd, p;
1369   PetscErrorCode ierr;
1370 
1371   PetscFunctionBegin;
1372   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1373   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1374   /* Calculate support sizes */
1375   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1376   for (p = pStart; p < pEnd; ++p) {
1377     PetscInt dof, off, c;
1378 
1379     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1380     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1381     for (c = off; c < off+dof; ++c) {
1382       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1383     }
1384   }
1385   for (p = pStart; p < pEnd; ++p) {
1386     PetscInt dof;
1387 
1388     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1389 
1390     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1391   }
1392   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1393   /* Calculate supports */
1394   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1395   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1396   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1397   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1398   for (p = pStart; p < pEnd; ++p) {
1399     PetscInt dof, off, c;
1400 
1401     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1402     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1403     for (c = off; c < off+dof; ++c) {
1404       const PetscInt q = mesh->cones[c];
1405       PetscInt       offS;
1406 
1407       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1408 
1409       mesh->supports[offS+offsets[q]] = p;
1410       ++offsets[q];
1411     }
1412   }
1413   ierr = PetscFree(offsets);CHKERRQ(ierr);
1414   PetscFunctionReturn(0);
1415 }
1416 
1417 #undef __FUNCT__
1418 #define __FUNCT__ "DMPlexSetDepth_Private"
1419 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1420 {
1421   PetscInt       d;
1422   PetscErrorCode ierr;
1423 
1424   PetscFunctionBegin;
1425   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1426   if (d < 0) {
1427     /* We are guaranteed that the point has a cone since the depth was not yet set */
1428     const PetscInt *cone = NULL;
1429     PetscInt        dCone;
1430 
1431     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1432     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1433     d    = dCone+1;
1434     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1435   }
1436   *depth = d;
1437   PetscFunctionReturn(0);
1438 }
1439 
1440 #undef __FUNCT__
1441 #define __FUNCT__ "DMPlexStratify"
1442 /*@
1443   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
1444   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
1445   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
1446   the DAG.
1447 
1448   Not collective
1449 
1450   Input Parameter:
1451 . mesh - The DMPlex
1452 
1453   Output Parameter:
1454 
1455   Notes:
1456   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
1457   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
1458 
1459   This should be called after all calls to DMPlexSymmetrize()
1460 
1461   Level: beginner
1462 
1463 .seealso: DMPlexCreate(), DMPlexSymmetrize()
1464 @*/
1465 PetscErrorCode DMPlexStratify(DM dm)
1466 {
1467   DM_Plex       *mesh = (DM_Plex*) dm->data;
1468   PetscInt       pStart, pEnd, p;
1469   PetscInt       numRoots = 0, numLeaves = 0;
1470   PetscErrorCode ierr;
1471 
1472   PetscFunctionBegin;
1473   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1474   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1475   /* Calculate depth */
1476   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1477   /* Initialize roots and count leaves */
1478   for (p = pStart; p < pEnd; ++p) {
1479     PetscInt coneSize, supportSize;
1480 
1481     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1482     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1483     if (!coneSize && supportSize) {
1484       ++numRoots;
1485       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
1486     } else if (!supportSize && coneSize) {
1487       ++numLeaves;
1488     } else if (!supportSize && !coneSize) {
1489       /* Isolated points */
1490       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
1491     }
1492   }
1493   if (numRoots + numLeaves == (pEnd - pStart)) {
1494     for (p = pStart; p < pEnd; ++p) {
1495       PetscInt coneSize, supportSize;
1496 
1497       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1498       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
1499       if (!supportSize && coneSize) {
1500         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
1501       }
1502     }
1503   } else {
1504     /* This might be slow since lookup is not fast */
1505     for (p = pStart; p < pEnd; ++p) {
1506       PetscInt depth;
1507 
1508       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
1509     }
1510   }
1511   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
1512   PetscFunctionReturn(0);
1513 }
1514 
1515 #undef __FUNCT__
1516 #define __FUNCT__ "DMPlexGetJoin"
1517 /*@C
1518   DMPlexGetJoin - Get an array for the join of the set of points
1519 
1520   Not Collective
1521 
1522   Input Parameters:
1523 + dm - The DMPlex object
1524 . numPoints - The number of input points for the join
1525 - points - The input points
1526 
1527   Output Parameters:
1528 + numCoveredPoints - The number of points in the join
1529 - coveredPoints - The points in the join
1530 
1531   Level: intermediate
1532 
1533   Note: Currently, this is restricted to a single level join
1534 
1535   Fortran Notes:
1536   Since it returns an array, this routine is only available in Fortran 90, and you must
1537   include petsc.h90 in your code.
1538 
1539   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1540 
1541 .keywords: mesh
1542 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
1543 @*/
1544 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1545 {
1546   DM_Plex       *mesh = (DM_Plex*) dm->data;
1547   PetscInt      *join[2];
1548   PetscInt       joinSize, i = 0;
1549   PetscInt       dof, off, p, c, m;
1550   PetscErrorCode ierr;
1551 
1552   PetscFunctionBegin;
1553   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1554   PetscValidPointer(points, 2);
1555   PetscValidPointer(numCoveredPoints, 3);
1556   PetscValidPointer(coveredPoints, 4);
1557   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1558   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1559   /* Copy in support of first point */
1560   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
1561   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
1562   for (joinSize = 0; joinSize < dof; ++joinSize) {
1563     join[i][joinSize] = mesh->supports[off+joinSize];
1564   }
1565   /* Check each successive support */
1566   for (p = 1; p < numPoints; ++p) {
1567     PetscInt newJoinSize = 0;
1568 
1569     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
1570     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
1571     for (c = 0; c < dof; ++c) {
1572       const PetscInt point = mesh->supports[off+c];
1573 
1574       for (m = 0; m < joinSize; ++m) {
1575         if (point == join[i][m]) {
1576           join[1-i][newJoinSize++] = point;
1577           break;
1578         }
1579       }
1580     }
1581     joinSize = newJoinSize;
1582     i        = 1-i;
1583   }
1584   *numCoveredPoints = joinSize;
1585   *coveredPoints    = join[i];
1586   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1587   PetscFunctionReturn(0);
1588 }
1589 
1590 #undef __FUNCT__
1591 #define __FUNCT__ "DMPlexRestoreJoin"
1592 /*@C
1593   DMPlexRestoreJoin - Restore an array for the join of the set of points
1594 
1595   Not Collective
1596 
1597   Input Parameters:
1598 + dm - The DMPlex object
1599 . numPoints - The number of input points for the join
1600 - points - The input points
1601 
1602   Output Parameters:
1603 + numCoveredPoints - The number of points in the join
1604 - coveredPoints - The points in the join
1605 
1606   Fortran Notes:
1607   Since it returns an array, this routine is only available in Fortran 90, and you must
1608   include petsc.h90 in your code.
1609 
1610   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1611 
1612   Level: intermediate
1613 
1614 .keywords: mesh
1615 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
1616 @*/
1617 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1618 {
1619   PetscErrorCode ierr;
1620 
1621   PetscFunctionBegin;
1622   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1623   PetscValidPointer(coveredPoints, 4);
1624   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1625   PetscFunctionReturn(0);
1626 }
1627 
1628 #undef __FUNCT__
1629 #define __FUNCT__ "DMPlexGetFullJoin"
1630 /*@C
1631   DMPlexGetFullJoin - Get an array for the join of the set of points
1632 
1633   Not Collective
1634 
1635   Input Parameters:
1636 + dm - The DMPlex object
1637 . numPoints - The number of input points for the join
1638 - points - The input points
1639 
1640   Output Parameters:
1641 + numCoveredPoints - The number of points in the join
1642 - coveredPoints - The points in the join
1643 
1644   Fortran Notes:
1645   Since it returns an array, this routine is only available in Fortran 90, and you must
1646   include petsc.h90 in your code.
1647 
1648   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1649 
1650   Level: intermediate
1651 
1652 .keywords: mesh
1653 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
1654 @*/
1655 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1656 {
1657   DM_Plex       *mesh = (DM_Plex*) dm->data;
1658   PetscInt      *offsets, **closures;
1659   PetscInt      *join[2];
1660   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
1661   PetscInt       p, d, c, m;
1662   PetscErrorCode ierr;
1663 
1664   PetscFunctionBegin;
1665   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1666   PetscValidPointer(points, 2);
1667   PetscValidPointer(numCoveredPoints, 3);
1668   PetscValidPointer(coveredPoints, 4);
1669 
1670   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1671   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1672   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
1673   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1674   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
1675   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
1676   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
1677 
1678   for (p = 0; p < numPoints; ++p) {
1679     PetscInt closureSize;
1680 
1681     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
1682 
1683     offsets[p*(depth+2)+0] = 0;
1684     for (d = 0; d < depth+1; ++d) {
1685       PetscInt pStart, pEnd, i;
1686 
1687       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
1688       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
1689         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1690           offsets[p*(depth+2)+d+1] = i;
1691           break;
1692         }
1693       }
1694       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
1695     }
1696     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
1697   }
1698   for (d = 0; d < depth+1; ++d) {
1699     PetscInt dof;
1700 
1701     /* Copy in support of first point */
1702     dof = offsets[d+1] - offsets[d];
1703     for (joinSize = 0; joinSize < dof; ++joinSize) {
1704       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
1705     }
1706     /* Check each successive cone */
1707     for (p = 1; p < numPoints && joinSize; ++p) {
1708       PetscInt newJoinSize = 0;
1709 
1710       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
1711       for (c = 0; c < dof; ++c) {
1712         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
1713 
1714         for (m = 0; m < joinSize; ++m) {
1715           if (point == join[i][m]) {
1716             join[1-i][newJoinSize++] = point;
1717             break;
1718           }
1719         }
1720       }
1721       joinSize = newJoinSize;
1722       i        = 1-i;
1723     }
1724     if (joinSize) break;
1725   }
1726   *numCoveredPoints = joinSize;
1727   *coveredPoints    = join[i];
1728   for (p = 0; p < numPoints; ++p) {
1729     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
1730   }
1731   ierr = PetscFree(closures);CHKERRQ(ierr);
1732   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1733   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
1734   PetscFunctionReturn(0);
1735 }
1736 
1737 #undef __FUNCT__
1738 #define __FUNCT__ "DMPlexGetMeet"
1739 /*@C
1740   DMPlexGetMeet - Get an array for the meet of the set of points
1741 
1742   Not Collective
1743 
1744   Input Parameters:
1745 + dm - The DMPlex object
1746 . numPoints - The number of input points for the meet
1747 - points - The input points
1748 
1749   Output Parameters:
1750 + numCoveredPoints - The number of points in the meet
1751 - coveredPoints - The points in the meet
1752 
1753   Level: intermediate
1754 
1755   Note: Currently, this is restricted to a single level meet
1756 
1757   Fortran Notes:
1758   Since it returns an array, this routine is only available in Fortran 90, and you must
1759   include petsc.h90 in your code.
1760 
1761   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1762 
1763 .keywords: mesh
1764 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
1765 @*/
1766 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
1767 {
1768   DM_Plex       *mesh = (DM_Plex*) dm->data;
1769   PetscInt      *meet[2];
1770   PetscInt       meetSize, i = 0;
1771   PetscInt       dof, off, p, c, m;
1772   PetscErrorCode ierr;
1773 
1774   PetscFunctionBegin;
1775   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1776   PetscValidPointer(points, 2);
1777   PetscValidPointer(numCoveringPoints, 3);
1778   PetscValidPointer(coveringPoints, 4);
1779   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1780   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1781   /* Copy in cone of first point */
1782   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
1783   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
1784   for (meetSize = 0; meetSize < dof; ++meetSize) {
1785     meet[i][meetSize] = mesh->cones[off+meetSize];
1786   }
1787   /* Check each successive cone */
1788   for (p = 1; p < numPoints; ++p) {
1789     PetscInt newMeetSize = 0;
1790 
1791     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
1792     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
1793     for (c = 0; c < dof; ++c) {
1794       const PetscInt point = mesh->cones[off+c];
1795 
1796       for (m = 0; m < meetSize; ++m) {
1797         if (point == meet[i][m]) {
1798           meet[1-i][newMeetSize++] = point;
1799           break;
1800         }
1801       }
1802     }
1803     meetSize = newMeetSize;
1804     i        = 1-i;
1805   }
1806   *numCoveringPoints = meetSize;
1807   *coveringPoints    = meet[i];
1808   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1809   PetscFunctionReturn(0);
1810 }
1811 
1812 #undef __FUNCT__
1813 #define __FUNCT__ "DMPlexRestoreMeet"
1814 /*@C
1815   DMPlexRestoreMeet - Restore an array for the meet of the set of points
1816 
1817   Not Collective
1818 
1819   Input Parameters:
1820 + dm - The DMPlex object
1821 . numPoints - The number of input points for the meet
1822 - points - The input points
1823 
1824   Output Parameters:
1825 + numCoveredPoints - The number of points in the meet
1826 - coveredPoints - The points in the meet
1827 
1828   Level: intermediate
1829 
1830   Fortran Notes:
1831   Since it returns an array, this routine is only available in Fortran 90, and you must
1832   include petsc.h90 in your code.
1833 
1834   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1835 
1836 .keywords: mesh
1837 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
1838 @*/
1839 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1840 {
1841   PetscErrorCode ierr;
1842 
1843   PetscFunctionBegin;
1844   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1845   PetscValidPointer(coveredPoints, 4);
1846   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
1847   PetscFunctionReturn(0);
1848 }
1849 
1850 #undef __FUNCT__
1851 #define __FUNCT__ "DMPlexGetFullMeet"
1852 /*@C
1853   DMPlexGetFullMeet - Get an array for the meet of the set of points
1854 
1855   Not Collective
1856 
1857   Input Parameters:
1858 + dm - The DMPlex object
1859 . numPoints - The number of input points for the meet
1860 - points - The input points
1861 
1862   Output Parameters:
1863 + numCoveredPoints - The number of points in the meet
1864 - coveredPoints - The points in the meet
1865 
1866   Level: intermediate
1867 
1868   Fortran Notes:
1869   Since it returns an array, this routine is only available in Fortran 90, and you must
1870   include petsc.h90 in your code.
1871 
1872   The numCoveredPoints argument is not present in the Fortran 90 binding since it is internal to the array.
1873 
1874 .keywords: mesh
1875 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
1876 @*/
1877 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
1878 {
1879   DM_Plex       *mesh = (DM_Plex*) dm->data;
1880   PetscInt      *offsets, **closures;
1881   PetscInt      *meet[2];
1882   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
1883   PetscInt       p, h, c, m;
1884   PetscErrorCode ierr;
1885 
1886   PetscFunctionBegin;
1887   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1888   PetscValidPointer(points, 2);
1889   PetscValidPointer(numCoveredPoints, 3);
1890   PetscValidPointer(coveredPoints, 4);
1891 
1892   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
1893   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
1894   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1895   maxSize = PetscPowInt(mesh->maxConeSize,height);
1896   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
1897   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
1898 
1899   for (p = 0; p < numPoints; ++p) {
1900     PetscInt closureSize;
1901 
1902     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
1903 
1904     offsets[p*(height+2)+0] = 0;
1905     for (h = 0; h < height+1; ++h) {
1906       PetscInt pStart, pEnd, i;
1907 
1908       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
1909       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
1910         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
1911           offsets[p*(height+2)+h+1] = i;
1912           break;
1913         }
1914       }
1915       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
1916     }
1917     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
1918   }
1919   for (h = 0; h < height+1; ++h) {
1920     PetscInt dof;
1921 
1922     /* Copy in cone of first point */
1923     dof = offsets[h+1] - offsets[h];
1924     for (meetSize = 0; meetSize < dof; ++meetSize) {
1925       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
1926     }
1927     /* Check each successive cone */
1928     for (p = 1; p < numPoints && meetSize; ++p) {
1929       PetscInt newMeetSize = 0;
1930 
1931       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
1932       for (c = 0; c < dof; ++c) {
1933         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
1934 
1935         for (m = 0; m < meetSize; ++m) {
1936           if (point == meet[i][m]) {
1937             meet[1-i][newMeetSize++] = point;
1938             break;
1939           }
1940         }
1941       }
1942       meetSize = newMeetSize;
1943       i        = 1-i;
1944     }
1945     if (meetSize) break;
1946   }
1947   *numCoveredPoints = meetSize;
1948   *coveredPoints    = meet[i];
1949   for (p = 0; p < numPoints; ++p) {
1950     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
1951   }
1952   ierr = PetscFree(closures);CHKERRQ(ierr);
1953   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
1954   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
1955   PetscFunctionReturn(0);
1956 }
1957 
1958 #undef __FUNCT__
1959 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
1960 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt cellDim, PetscInt numCorners, PetscInt *numFaceVertices)
1961 {
1962   MPI_Comm       comm;
1963   PetscErrorCode ierr;
1964 
1965   PetscFunctionBegin;
1966   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1967   PetscValidPointer(numFaceVertices,3);
1968   switch (cellDim) {
1969   case 0:
1970     *numFaceVertices = 0;
1971     break;
1972   case 1:
1973     *numFaceVertices = 1;
1974     break;
1975   case 2:
1976     switch (numCorners) {
1977     case 3: /* triangle */
1978       *numFaceVertices = 2; /* Edge has 2 vertices */
1979       break;
1980     case 4: /* quadrilateral */
1981       *numFaceVertices = 2; /* Edge has 2 vertices */
1982       break;
1983     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
1984       *numFaceVertices = 3; /* Edge has 3 vertices */
1985       break;
1986     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
1987       *numFaceVertices = 3; /* Edge has 3 vertices */
1988       break;
1989     default:
1990       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
1991     }
1992     break;
1993   case 3:
1994     switch (numCorners) {
1995     case 4: /* tetradehdron */
1996       *numFaceVertices = 3; /* Face has 3 vertices */
1997       break;
1998     case 6: /* tet cohesive cells */
1999       *numFaceVertices = 4; /* Face has 4 vertices */
2000       break;
2001     case 8: /* hexahedron */
2002       *numFaceVertices = 4; /* Face has 4 vertices */
2003       break;
2004     case 9: /* tet cohesive Lagrange cells */
2005       *numFaceVertices = 6; /* Face has 6 vertices */
2006       break;
2007     case 10: /* quadratic tetrahedron */
2008       *numFaceVertices = 6; /* Face has 6 vertices */
2009       break;
2010     case 12: /* hex cohesive Lagrange cells */
2011       *numFaceVertices = 6; /* Face has 6 vertices */
2012       break;
2013     case 18: /* quadratic tet cohesive Lagrange cells */
2014       *numFaceVertices = 6; /* Face has 6 vertices */
2015       break;
2016     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2017       *numFaceVertices = 9; /* Face has 9 vertices */
2018       break;
2019     default:
2020       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2021     }
2022     break;
2023   default:
2024     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2025   }
2026   PetscFunctionReturn(0);
2027 }
2028 
2029 #undef __FUNCT__
2030 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Internal"
2031 static PetscErrorCode DMPlexGetAdjacencySingleLevel_Internal(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
2032 {
2033   const PetscInt *support = NULL;
2034   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
2035   PetscErrorCode  ierr;
2036 
2037   PetscFunctionBegin;
2038   if (useClosure) {
2039     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
2040     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
2041     for (s = 0; s < supportSize; ++s) {
2042       const PetscInt *cone = NULL;
2043       PetscInt        coneSize, c, q;
2044 
2045       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2046       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
2047       for (c = 0; c < coneSize; ++c) {
2048         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2049           if (cone[c] == adj[q]) break;
2050         }
2051         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2052       }
2053     }
2054   } else {
2055     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2056     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
2057     for (s = 0; s < supportSize; ++s) {
2058       const PetscInt *cone = NULL;
2059       PetscInt        coneSize, c, q;
2060 
2061       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
2062       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
2063       for (c = 0; c < coneSize; ++c) {
2064         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
2065           if (cone[c] == adj[q]) break;
2066         }
2067         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
2068       }
2069     }
2070   }
2071   *adjSize = numAdj;
2072   PetscFunctionReturn(0);
2073 }
2074 
2075 #undef __FUNCT__
2076 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2077 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt cellHeight, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2078 {
2079   const PetscInt maxFaceCases = 30;
2080   PetscInt       numFaceCases = 0;
2081   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2082   PetscInt      *off, *adj;
2083   PetscInt      *neighborCells, *tmpClosure;
2084   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2085   PetscInt       dim, cellDim, depth = 0, faceDepth, cStart, cEnd, c, numCells, cell;
2086   PetscErrorCode ierr;
2087 
2088   PetscFunctionBegin;
2089   /* For parallel partitioning, I think you have to communicate supports */
2090   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2091   cellDim = dim - cellHeight;
2092   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2093   ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
2094   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2095   if (cEnd - cStart == 0) {
2096     if (numVertices) *numVertices = 0;
2097     if (offsets)   *offsets   = NULL;
2098     if (adjacency) *adjacency = NULL;
2099     PetscFunctionReturn(0);
2100   }
2101   numCells  = cEnd - cStart;
2102   faceDepth = depth - cellHeight;
2103   /* Setup face recognition */
2104   if (faceDepth == 1) {
2105     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 */
2106 
2107     for (c = cStart; c < cEnd; ++c) {
2108       PetscInt corners;
2109 
2110       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2111       if (!cornersSeen[corners]) {
2112         PetscInt nFV;
2113 
2114         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2115         cornersSeen[corners] = 1;
2116 
2117         ierr = DMPlexGetNumFaceVertices_Internal(dm, cellDim, corners, &nFV);CHKERRQ(ierr);
2118 
2119         numFaceVertices[numFaceCases++] = nFV;
2120       }
2121     }
2122   }
2123   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2124   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2125   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2126   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2127   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2128   /* Count neighboring cells */
2129   for (cell = cStart; cell < cEnd; ++cell) {
2130     PetscInt numNeighbors = maxNeighbors, n;
2131 
2132     ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2133     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2134     for (n = 0; n < numNeighbors; ++n) {
2135       PetscInt        cellPair[2];
2136       PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2137       PetscInt        meetSize = 0;
2138       const PetscInt *meet    = NULL;
2139 
2140       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2141       if (cellPair[0] == cellPair[1]) continue;
2142       if (!found) {
2143         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2144         if (meetSize) {
2145           PetscInt f;
2146 
2147           for (f = 0; f < numFaceCases; ++f) {
2148             if (numFaceVertices[f] == meetSize) {
2149               found = PETSC_TRUE;
2150               break;
2151             }
2152           }
2153         }
2154         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2155       }
2156       if (found) ++off[cell-cStart+1];
2157     }
2158   }
2159   /* Prefix sum */
2160   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2161 
2162   if (adjacency) {
2163     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2164     /* Get neighboring cells */
2165     for (cell = cStart; cell < cEnd; ++cell) {
2166       PetscInt numNeighbors = maxNeighbors, n;
2167       PetscInt cellOffset   = 0;
2168 
2169       ierr = DMPlexGetAdjacencySingleLevel_Internal(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2170       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2171       for (n = 0; n < numNeighbors; ++n) {
2172         PetscInt        cellPair[2];
2173         PetscBool       found    = faceDepth > 1 ? PETSC_TRUE : PETSC_FALSE;
2174         PetscInt        meetSize = 0;
2175         const PetscInt *meet    = NULL;
2176 
2177         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2178         if (cellPair[0] == cellPair[1]) continue;
2179         if (!found) {
2180           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2181           if (meetSize) {
2182             PetscInt f;
2183 
2184             for (f = 0; f < numFaceCases; ++f) {
2185               if (numFaceVertices[f] == meetSize) {
2186                 found = PETSC_TRUE;
2187                 break;
2188               }
2189             }
2190           }
2191           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2192         }
2193         if (found) {
2194           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2195           ++cellOffset;
2196         }
2197       }
2198     }
2199   }
2200   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2201   if (numVertices) *numVertices = numCells;
2202   if (offsets)   *offsets   = off;
2203   if (adjacency) *adjacency = adj;
2204   PetscFunctionReturn(0);
2205 }
2206 
2207 #if defined(PETSC_HAVE_CHACO)
2208 #if defined(PETSC_HAVE_UNISTD_H)
2209 #include <unistd.h>
2210 #endif
2211 /* Chaco does not have an include file */
2212 PETSC_EXTERN int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2213                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2214                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2215                        int mesh_dims[3], double *goal, int global_method, int local_method,
2216                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2217 
2218 extern int FREE_GRAPH;
2219 
2220 #undef __FUNCT__
2221 #define __FUNCT__ "DMPlexPartition_Chaco"
2222 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2223 {
2224   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2225   MPI_Comm       comm;
2226   int            nvtxs          = numVertices; /* number of vertices in full graph */
2227   int           *vwgts          = NULL;   /* weights for all vertices */
2228   float         *ewgts          = NULL;   /* weights for all edges */
2229   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2230   char          *outassignname  = NULL;   /*  name of assignment output file */
2231   char          *outfilename    = NULL;   /* output file name */
2232   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2233   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2234   int            mesh_dims[3];            /* dimensions of mesh of processors */
2235   double        *goal          = NULL;    /* desired set sizes for each set */
2236   int            global_method = 1;       /* global partitioning algorithm */
2237   int            local_method  = 1;       /* local partitioning algorithm */
2238   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2239   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2240   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2241   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2242   long           seed          = 123636512; /* for random graph mutations */
2243   short int     *assignment;              /* Output partition */
2244   int            fd_stdout, fd_pipe[2];
2245   PetscInt      *points;
2246   PetscMPIInt    commSize;
2247   int            i, v, p;
2248   PetscErrorCode ierr;
2249 
2250   PetscFunctionBegin;
2251   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2252   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2253   if (!numVertices) {
2254     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2255     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2256     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2257     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2258     PetscFunctionReturn(0);
2259   }
2260   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2261   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2262 
2263   if (global_method == INERTIAL_METHOD) {
2264     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2265     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2266   }
2267   mesh_dims[0] = commSize;
2268   mesh_dims[1] = 1;
2269   mesh_dims[2] = 1;
2270   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2271   /* Chaco outputs to stdout. We redirect this to a buffer. */
2272   /* TODO: check error codes for UNIX calls */
2273 #if defined(PETSC_HAVE_UNISTD_H)
2274   {
2275     int piperet;
2276     piperet = pipe(fd_pipe);
2277     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2278     fd_stdout = dup(1);
2279     close(1);
2280     dup2(fd_pipe[1], 1);
2281   }
2282 #endif
2283   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2284                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2285                    vmax, ndims, eigtol, seed);
2286 #if defined(PETSC_HAVE_UNISTD_H)
2287   {
2288     char msgLog[10000];
2289     int  count;
2290 
2291     fflush(stdout);
2292     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2293     if (count < 0) count = 0;
2294     msgLog[count] = 0;
2295     close(1);
2296     dup2(fd_stdout, 1);
2297     close(fd_stdout);
2298     close(fd_pipe[0]);
2299     close(fd_pipe[1]);
2300     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2301   }
2302 #endif
2303   /* Convert to PetscSection+IS */
2304   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2305   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2306   for (v = 0; v < nvtxs; ++v) {
2307     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2308   }
2309   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2310   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2311   for (p = 0, i = 0; p < commSize; ++p) {
2312     for (v = 0; v < nvtxs; ++v) {
2313       if (assignment[v] == p) points[i++] = v;
2314     }
2315   }
2316   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2317   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2318   if (global_method == INERTIAL_METHOD) {
2319     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2320   }
2321   ierr = PetscFree(assignment);CHKERRQ(ierr);
2322   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2323   PetscFunctionReturn(0);
2324 }
2325 #endif
2326 
2327 #if defined(PETSC_HAVE_PARMETIS)
2328 #undef __FUNCT__
2329 #define __FUNCT__ "DMPlexPartition_ParMetis"
2330 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2331 {
2332   PetscFunctionBegin;
2333   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2334   PetscFunctionReturn(0);
2335 }
2336 #endif
2337 
2338 #undef __FUNCT__
2339 #define __FUNCT__ "DMPlexEnlargePartition"
2340 /* Expand the partition by BFS on the adjacency graph */
2341 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2342 {
2343   PetscHashI      h;
2344   const PetscInt *points;
2345   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2346   PetscInt        pStart, pEnd, part, q;
2347   PetscErrorCode  ierr;
2348 
2349   PetscFunctionBegin;
2350   PetscHashICreate(h);
2351   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2352   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2353   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2354   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2355   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2356   for (part = pStart; part < pEnd; ++part) {
2357     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2358 
2359     PetscHashIClear(h);
2360     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2361     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2362     /* Add all existing points to h */
2363     for (p = 0; p < numPoints; ++p) {
2364       const PetscInt point = points[off+p];
2365       PetscHashIAdd(h, point, 1);
2366     }
2367     PetscHashISize(h, nP);
2368     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2369     /* Add all points in next BFS level */
2370     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2371     for (p = 0; p < numPoints; ++p) {
2372       const PetscInt point = points[off+p];
2373       PetscInt       s     = start[point], e = start[point+1], a;
2374 
2375       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2376     }
2377     PetscHashISize(h, numNewPoints);
2378     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2379     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2380     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2381     totPoints += numNewPoints;
2382   }
2383   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2384   PetscHashIDestroy(h);
2385   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2386   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2387   for (part = pStart, q = 0; part < pEnd; ++part) {
2388     PetscInt numPoints, p;
2389 
2390     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2391     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2392     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2393   }
2394   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2395   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2396   PetscFunctionReturn(0);
2397 }
2398 
2399 #undef __FUNCT__
2400 #define __FUNCT__ "DMPlexCreatePartition"
2401 /*
2402   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2403 
2404   Collective on DM
2405 
2406   Input Parameters:
2407   + dm - The DM
2408   . height - The height for points in the partition
2409   - enlarge - Expand each partition with neighbors
2410 
2411   Output Parameters:
2412   + partSection - The PetscSection giving the division of points by partition
2413   . partition - The list of points by partition
2414   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2415   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2416 
2417   Level: developer
2418 
2419 .seealso DMPlexDistribute()
2420 */
2421 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2422 {
2423   PetscMPIInt    size;
2424   PetscErrorCode ierr;
2425 
2426   PetscFunctionBegin;
2427   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2428 
2429   *origPartSection = NULL;
2430   *origPartition   = NULL;
2431   if (size == 1) {
2432     PetscInt *points;
2433     PetscInt  cStart, cEnd, c;
2434 
2435     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2436     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2437     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2438     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2439     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2440     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2441     for (c = cStart; c < cEnd; ++c) points[c] = c;
2442     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2443     PetscFunctionReturn(0);
2444   }
2445   if (height == 0) {
2446     PetscInt  numVertices;
2447     PetscInt *start     = NULL;
2448     PetscInt *adjacency = NULL;
2449 
2450     ierr = DMPlexCreateNeighborCSR(dm, 0, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2451     if (1) {
2452 #if defined(PETSC_HAVE_CHACO)
2453       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2454 #endif
2455     } else {
2456 #if defined(PETSC_HAVE_PARMETIS)
2457       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2458 #endif
2459     }
2460     if (enlarge) {
2461       *origPartSection = *partSection;
2462       *origPartition   = *partition;
2463 
2464       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2465     }
2466     ierr = PetscFree(start);CHKERRQ(ierr);
2467     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2468 # if 0
2469   } else if (height == 1) {
2470     /* Build the dual graph for faces and partition the hypergraph */
2471     PetscInt numEdges;
2472 
2473     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2474     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2475     destroyCSR(numEdges, start, adjacency);
2476 #endif
2477   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2478   PetscFunctionReturn(0);
2479 }
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2483 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2484 {
2485   /* const PetscInt  height = 0; */
2486   const PetscInt *partArray;
2487   PetscInt       *allPoints, *partPoints = NULL;
2488   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2489   PetscErrorCode  ierr;
2490 
2491   PetscFunctionBegin;
2492   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2493   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2494   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2495   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2496   for (rank = rStart; rank < rEnd; ++rank) {
2497     PetscInt partSize = 0;
2498     PetscInt numPoints, offset, p;
2499 
2500     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2501     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2502     for (p = 0; p < numPoints; ++p) {
2503       PetscInt  point   = partArray[offset+p], closureSize, c;
2504       PetscInt *closure = NULL;
2505 
2506       /* TODO Include support for height > 0 case */
2507       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2508       /* Merge into existing points */
2509       if (partSize+closureSize > maxPartSize) {
2510         PetscInt *tmpPoints;
2511 
2512         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2513         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2514         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2515         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2516 
2517         partPoints = tmpPoints;
2518       }
2519       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2520       partSize += closureSize;
2521 
2522       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2523       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2524     }
2525     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2526   }
2527   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2528   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2529   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2530 
2531   for (rank = rStart; rank < rEnd; ++rank) {
2532     PetscInt partSize = 0, newOffset;
2533     PetscInt numPoints, offset, p;
2534 
2535     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2536     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2537     for (p = 0; p < numPoints; ++p) {
2538       PetscInt  point   = partArray[offset+p], closureSize, c;
2539       PetscInt *closure = NULL;
2540 
2541       /* TODO Include support for height > 0 case */
2542       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2543       /* Merge into existing points */
2544       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2545       partSize += closureSize;
2546 
2547       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2548       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2549     }
2550     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
2551     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2552   }
2553   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2554   ierr = PetscFree(partPoints);CHKERRQ(ierr);
2555   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2556   PetscFunctionReturn(0);
2557 }
2558 
2559 #undef __FUNCT__
2560 #define __FUNCT__ "DMPlexDistributeField"
2561 /*
2562   Input Parameters:
2563 . originalSection
2564 , originalVec
2565 
2566   Output Parameters:
2567 . newSection
2568 . newVec
2569 */
2570 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2571 {
2572   PetscSF        fieldSF;
2573   PetscInt      *remoteOffsets, fieldSize;
2574   PetscScalar   *originalValues, *newValues;
2575   PetscErrorCode ierr;
2576 
2577   PetscFunctionBegin;
2578   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
2579 
2580   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
2581   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
2582   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
2583 
2584   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
2585   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
2586   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2587   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2588   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2589   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2590   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
2591   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
2592   PetscFunctionReturn(0);
2593 }
2594 
2595 #undef __FUNCT__
2596 #define __FUNCT__ "DMPlexDistribute"
2597 /*@C
2598   DMPlexDistribute - Distributes the mesh and any associated sections.
2599 
2600   Not Collective
2601 
2602   Input Parameter:
2603 + dm  - The original DMPlex object
2604 . partitioner - The partitioning package, or NULL for the default
2605 - overlap - The overlap of partitions, 0 is the default
2606 
2607   Output Parameter:
2608 . parallelMesh - The distributed DMPlex object, or NULL
2609 
2610   Note: If the mesh was not distributed, the return value is NULL
2611 
2612   Level: intermediate
2613 
2614 .keywords: mesh, elements
2615 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2616 @*/
2617 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
2618 {
2619   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2620   MPI_Comm               comm;
2621   const PetscInt         height = 0;
2622   PetscInt               dim, numRemoteRanks;
2623   IS                     origCellPart,        cellPart,        part;
2624   PetscSection           origCellPartSection, cellPartSection, partSection;
2625   PetscSFNode           *remoteRanks;
2626   PetscSF                partSF, pointSF, coneSF;
2627   ISLocalToGlobalMapping renumbering;
2628   PetscSection           originalConeSection, newConeSection;
2629   PetscInt              *remoteOffsets;
2630   PetscInt              *cones, *newCones, newConesSize;
2631   PetscBool              flg;
2632   PetscMPIInt            rank, numProcs, p;
2633   PetscErrorCode         ierr;
2634 
2635   PetscFunctionBegin;
2636   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2637   PetscValidPointer(dmParallel,4);
2638 
2639   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2640   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2641   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2642   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
2643 
2644   *dmParallel = NULL;
2645   if (numProcs == 1) PetscFunctionReturn(0);
2646 
2647   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2648   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2649   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2650   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
2651   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2652   if (!rank) numRemoteRanks = numProcs;
2653   else       numRemoteRanks = 0;
2654   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
2655   for (p = 0; p < numRemoteRanks; ++p) {
2656     remoteRanks[p].rank  = p;
2657     remoteRanks[p].index = 0;
2658   }
2659   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
2660   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
2661   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
2662   if (flg) {
2663     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
2664     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2665     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
2666     if (origCellPart) {
2667       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
2668       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2669       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
2670     }
2671     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
2672   }
2673   /* Close the partition over the mesh */
2674   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
2675   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
2676   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
2677   /* Create new mesh */
2678   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
2679   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
2680   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
2681   pmesh = (DM_Plex*) (*dmParallel)->data;
2682   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
2683   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
2684   if (flg) {
2685     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
2686     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2687     ierr = ISView(part, NULL);CHKERRQ(ierr);
2688     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
2689     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
2690     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
2691   }
2692   /* Distribute cone section */
2693   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
2694   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
2695   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
2696   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
2697   {
2698     PetscInt pStart, pEnd, p;
2699 
2700     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
2701     for (p = pStart; p < pEnd; ++p) {
2702       PetscInt coneSize;
2703       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
2704       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
2705     }
2706   }
2707   /* Communicate and renumber cones */
2708   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
2709   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2710   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
2711   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2712   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2713   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
2714   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
2715   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
2716   if (flg) {
2717     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
2718     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2719     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
2720     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2721     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
2722   }
2723   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
2724   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
2725   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2726   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2727   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
2728   /* Create supports and stratify sieve */
2729   {
2730     PetscInt pStart, pEnd;
2731 
2732     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2733     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2734   }
2735   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
2736   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
2737   /* Distribute Coordinates */
2738   {
2739     PetscSection originalCoordSection, newCoordSection;
2740     Vec          originalCoordinates, newCoordinates;
2741     const char  *name;
2742 
2743     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
2744     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
2745     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
2746     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
2747     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
2748     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
2749 
2750     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
2751     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
2752     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
2753   }
2754   /* Distribute labels */
2755   {
2756     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
2757     PetscInt numLabels = 0, l;
2758 
2759     /* Bcast number of labels */
2760     while (next) {
2761       ++numLabels; next = next->next;
2762     }
2763     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2764     next = mesh->labels;
2765     for (l = 0; l < numLabels; ++l) {
2766       DMLabel         newLabel;
2767       const PetscInt *partArray;
2768       char           *name;
2769       PetscInt       *stratumSizes = NULL, *points = NULL;
2770       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
2771       PetscInt        nameSize, s, p;
2772       PetscBool       isdepth;
2773       size_t          len = 0;
2774 
2775       /* Bcast name (could filter for no points) */
2776       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
2777       nameSize = len;
2778       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2779       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
2780       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
2781       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
2782       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
2783       if (isdepth) {            /* skip because "depth" is not distributed */
2784         ierr = PetscFree(name);CHKERRQ(ierr);
2785         if (!rank) next = next->next;
2786         continue;
2787       }
2788       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
2789       newLabel->name = name;
2790       /* Bcast numStrata (could filter for no points in stratum) */
2791       if (!rank) newLabel->numStrata = next->numStrata;
2792       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2793       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
2794                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
2795                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
2796       /* Bcast stratumValues (could filter for no points in stratum) */
2797       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
2798       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2799       /* Find size on each process and Scatter */
2800       if (!rank) {
2801         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
2802         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
2803         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
2804         for (s = 0; s < next->numStrata; ++s) {
2805           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2806             const PetscInt point = next->points[p];
2807             PetscInt       proc;
2808 
2809             for (proc = 0; proc < numProcs; ++proc) {
2810               PetscInt dof, off, pPart;
2811 
2812               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2813               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2814               for (pPart = off; pPart < off+dof; ++pPart) {
2815                 if (partArray[pPart] == point) {
2816                   ++stratumSizes[proc*next->numStrata+s];
2817                   break;
2818                 }
2819               }
2820             }
2821           }
2822         }
2823         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
2824       }
2825       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2826       /* Calculate stratumOffsets */
2827       newLabel->stratumOffsets[0] = 0;
2828       for (s = 0; s < newLabel->numStrata; ++s) {
2829         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
2830       }
2831       /* Pack points and Scatter */
2832       if (!rank) {
2833         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
2834         displs[0] = 0;
2835         for (p = 0; p < numProcs; ++p) {
2836           sendcnts[p] = 0;
2837           for (s = 0; s < next->numStrata; ++s) {
2838             sendcnts[p] += stratumSizes[p*next->numStrata+s];
2839           }
2840           offsets[p]  = displs[p];
2841           displs[p+1] = displs[p] + sendcnts[p];
2842         }
2843         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
2844         for (s = 0; s < next->numStrata; ++s) {
2845           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2846             const PetscInt point = next->points[p];
2847             PetscInt       proc;
2848 
2849             for (proc = 0; proc < numProcs; ++proc) {
2850               PetscInt dof, off, pPart;
2851 
2852               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2853               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2854               for (pPart = off; pPart < off+dof; ++pPart) {
2855                 if (partArray[pPart] == point) {
2856                   points[offsets[proc]++] = point;
2857                   break;
2858                 }
2859               }
2860             }
2861           }
2862         }
2863       }
2864       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
2865       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
2866       ierr = PetscFree(points);CHKERRQ(ierr);
2867       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
2868       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
2869       /* Renumber points */
2870       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
2871       /* Sort points */
2872       for (s = 0; s < newLabel->numStrata; ++s) {
2873         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
2874       }
2875       /* Insert into list */
2876       if (newNext) newNext->next = newLabel;
2877       else pmesh->labels = newLabel;
2878       newNext = newLabel;
2879       if (!rank) next = next->next;
2880     }
2881   }
2882   /* Cleanup Partition */
2883   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
2884   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
2885   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
2886   ierr = ISDestroy(&part);CHKERRQ(ierr);
2887   /* Create point SF for parallel mesh */
2888   {
2889     const PetscInt *leaves;
2890     PetscSFNode    *remotePoints, *rowners, *lowners;
2891     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
2892     PetscInt        pStart, pEnd;
2893 
2894     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
2895     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
2896     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
2897     for (p=0; p<numRoots; p++) {
2898       rowners[p].rank  = -1;
2899       rowners[p].index = -1;
2900     }
2901     if (origCellPart) {
2902       /* Make sure cells in the original partition are not assigned to other procs */
2903       const PetscInt *origCells;
2904 
2905       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
2906       for (p = 0; p < numProcs; ++p) {
2907         PetscInt dof, off, d;
2908 
2909         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
2910         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
2911         for (d = off; d < off+dof; ++d) {
2912           rowners[origCells[d]].rank = p;
2913         }
2914       }
2915       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
2916     }
2917     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
2918     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
2919 
2920     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2921     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2922     for (p = 0; p < numLeaves; ++p) {
2923       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
2924         lowners[p].rank  = rank;
2925         lowners[p].index = leaves ? leaves[p] : p;
2926       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
2927         lowners[p].rank  = -2;
2928         lowners[p].index = -2;
2929       }
2930     }
2931     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
2932       rowners[p].rank  = -3;
2933       rowners[p].index = -3;
2934     }
2935     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
2936     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
2937     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2938     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2939     for (p = 0; p < numLeaves; ++p) {
2940       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
2941       if (lowners[p].rank != rank) ++numGhostPoints;
2942     }
2943     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
2944     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
2945     for (p = 0, gp = 0; p < numLeaves; ++p) {
2946       if (lowners[p].rank != rank) {
2947         ghostPoints[gp]        = leaves ? leaves[p] : p;
2948         remotePoints[gp].rank  = lowners[p].rank;
2949         remotePoints[gp].index = lowners[p].index;
2950         ++gp;
2951       }
2952     }
2953     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
2954     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
2955     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
2956   }
2957   /* Cleanup */
2958   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
2959   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
2960   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2961   PetscFunctionReturn(0);
2962 }
2963 
2964 #if defined(PETSC_HAVE_TRIANGLE)
2965 #include <triangle.h>
2966 
2967 #undef __FUNCT__
2968 #define __FUNCT__ "InitInput_Triangle"
2969 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
2970 {
2971   PetscFunctionBegin;
2972   inputCtx->numberofpoints             = 0;
2973   inputCtx->numberofpointattributes    = 0;
2974   inputCtx->pointlist                  = NULL;
2975   inputCtx->pointattributelist         = NULL;
2976   inputCtx->pointmarkerlist            = NULL;
2977   inputCtx->numberofsegments           = 0;
2978   inputCtx->segmentlist                = NULL;
2979   inputCtx->segmentmarkerlist          = NULL;
2980   inputCtx->numberoftriangleattributes = 0;
2981   inputCtx->trianglelist               = NULL;
2982   inputCtx->numberofholes              = 0;
2983   inputCtx->holelist                   = NULL;
2984   inputCtx->numberofregions            = 0;
2985   inputCtx->regionlist                 = NULL;
2986   PetscFunctionReturn(0);
2987 }
2988 
2989 #undef __FUNCT__
2990 #define __FUNCT__ "InitOutput_Triangle"
2991 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
2992 {
2993   PetscFunctionBegin;
2994   outputCtx->numberofpoints        = 0;
2995   outputCtx->pointlist             = NULL;
2996   outputCtx->pointattributelist    = NULL;
2997   outputCtx->pointmarkerlist       = NULL;
2998   outputCtx->numberoftriangles     = 0;
2999   outputCtx->trianglelist          = NULL;
3000   outputCtx->triangleattributelist = NULL;
3001   outputCtx->neighborlist          = NULL;
3002   outputCtx->segmentlist           = NULL;
3003   outputCtx->segmentmarkerlist     = NULL;
3004   outputCtx->numberofedges         = 0;
3005   outputCtx->edgelist              = NULL;
3006   outputCtx->edgemarkerlist        = NULL;
3007   PetscFunctionReturn(0);
3008 }
3009 
3010 #undef __FUNCT__
3011 #define __FUNCT__ "FiniOutput_Triangle"
3012 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3013 {
3014   PetscFunctionBegin;
3015   free(outputCtx->pointmarkerlist);
3016   free(outputCtx->edgelist);
3017   free(outputCtx->edgemarkerlist);
3018   free(outputCtx->trianglelist);
3019   free(outputCtx->neighborlist);
3020   PetscFunctionReturn(0);
3021 }
3022 
3023 #undef __FUNCT__
3024 #define __FUNCT__ "DMPlexGenerate_Triangle"
3025 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3026 {
3027   MPI_Comm             comm;
3028   PetscInt             dim              = 2;
3029   const PetscBool      createConvexHull = PETSC_FALSE;
3030   const PetscBool      constrained      = PETSC_FALSE;
3031   struct triangulateio in;
3032   struct triangulateio out;
3033   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3034   PetscMPIInt          rank;
3035   PetscErrorCode       ierr;
3036 
3037   PetscFunctionBegin;
3038   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3039   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3040   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3041   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3042   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3043 
3044   in.numberofpoints = vEnd - vStart;
3045   if (in.numberofpoints > 0) {
3046     PetscSection coordSection;
3047     Vec          coordinates;
3048     PetscScalar *array;
3049 
3050     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3051     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3052     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3053     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3054     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3055     for (v = vStart; v < vEnd; ++v) {
3056       const PetscInt idx = v - vStart;
3057       PetscInt       off, d;
3058 
3059       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3060       for (d = 0; d < dim; ++d) {
3061         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3062       }
3063       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3064     }
3065     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3066   }
3067   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3068   in.numberofsegments = eEnd - eStart;
3069   if (in.numberofsegments > 0) {
3070     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3071     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3072     for (e = eStart; e < eEnd; ++e) {
3073       const PetscInt  idx = e - eStart;
3074       const PetscInt *cone;
3075 
3076       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3077 
3078       in.segmentlist[idx*2+0] = cone[0] - vStart;
3079       in.segmentlist[idx*2+1] = cone[1] - vStart;
3080 
3081       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3082     }
3083   }
3084 #if 0 /* Do not currently support holes */
3085   PetscReal *holeCoords;
3086   PetscInt   h, d;
3087 
3088   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3089   if (in.numberofholes > 0) {
3090     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3091     for (h = 0; h < in.numberofholes; ++h) {
3092       for (d = 0; d < dim; ++d) {
3093         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3094       }
3095     }
3096   }
3097 #endif
3098   if (!rank) {
3099     char args[32];
3100 
3101     /* Take away 'Q' for verbose output */
3102     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3103     if (createConvexHull) {
3104       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3105     }
3106     if (constrained) {
3107       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3108     }
3109     triangulate(args, &in, &out, NULL);
3110   }
3111   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3112   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3113   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3114   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3115   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3116 
3117   {
3118     const PetscInt numCorners  = 3;
3119     const PetscInt numCells    = out.numberoftriangles;
3120     const PetscInt numVertices = out.numberofpoints;
3121     const int     *cells      = out.trianglelist;
3122     const double  *meshCoords = out.pointlist;
3123 
3124     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3125     /* Set labels */
3126     for (v = 0; v < numVertices; ++v) {
3127       if (out.pointmarkerlist[v]) {
3128         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3129       }
3130     }
3131     if (interpolate) {
3132       for (e = 0; e < out.numberofedges; e++) {
3133         if (out.edgemarkerlist[e]) {
3134           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3135           const PetscInt *edges;
3136           PetscInt        numEdges;
3137 
3138           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3139           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3140           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3141           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3142         }
3143       }
3144     }
3145     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3146   }
3147 #if 0 /* Do not currently support holes */
3148   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3149 #endif
3150   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3151   PetscFunctionReturn(0);
3152 }
3153 
3154 #undef __FUNCT__
3155 #define __FUNCT__ "DMPlexRefine_Triangle"
3156 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3157 {
3158   MPI_Comm             comm;
3159   PetscInt             dim  = 2;
3160   struct triangulateio in;
3161   struct triangulateio out;
3162   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3163   PetscMPIInt          rank;
3164   PetscErrorCode       ierr;
3165 
3166   PetscFunctionBegin;
3167   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3168   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3169   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3170   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3171   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3172   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3173   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3174 
3175   in.numberofpoints = vEnd - vStart;
3176   if (in.numberofpoints > 0) {
3177     PetscSection coordSection;
3178     Vec          coordinates;
3179     PetscScalar *array;
3180 
3181     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3182     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3183     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3184     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3185     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3186     for (v = vStart; v < vEnd; ++v) {
3187       const PetscInt idx = v - vStart;
3188       PetscInt       off, d;
3189 
3190       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3191       for (d = 0; d < dim; ++d) {
3192         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3193       }
3194       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3195     }
3196     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3197   }
3198   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3199 
3200   in.numberofcorners   = 3;
3201   in.numberoftriangles = cEnd - cStart;
3202 
3203   in.trianglearealist  = (double*) maxVolumes;
3204   if (in.numberoftriangles > 0) {
3205     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3206     for (c = cStart; c < cEnd; ++c) {
3207       const PetscInt idx      = c - cStart;
3208       PetscInt      *closure = NULL;
3209       PetscInt       closureSize;
3210 
3211       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3212       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3213       for (v = 0; v < 3; ++v) {
3214         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3215       }
3216       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3217     }
3218   }
3219   /* TODO: Segment markers are missing on input */
3220 #if 0 /* Do not currently support holes */
3221   PetscReal *holeCoords;
3222   PetscInt   h, d;
3223 
3224   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3225   if (in.numberofholes > 0) {
3226     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3227     for (h = 0; h < in.numberofholes; ++h) {
3228       for (d = 0; d < dim; ++d) {
3229         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3230       }
3231     }
3232   }
3233 #endif
3234   if (!rank) {
3235     char args[32];
3236 
3237     /* Take away 'Q' for verbose output */
3238     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3239     triangulate(args, &in, &out, NULL);
3240   }
3241   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3242   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3243   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3244   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3245   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3246 
3247   {
3248     const PetscInt numCorners  = 3;
3249     const PetscInt numCells    = out.numberoftriangles;
3250     const PetscInt numVertices = out.numberofpoints;
3251     const int     *cells      = out.trianglelist;
3252     const double  *meshCoords = out.pointlist;
3253     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3254 
3255     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3256     /* Set labels */
3257     for (v = 0; v < numVertices; ++v) {
3258       if (out.pointmarkerlist[v]) {
3259         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3260       }
3261     }
3262     if (interpolate) {
3263       PetscInt e;
3264 
3265       for (e = 0; e < out.numberofedges; e++) {
3266         if (out.edgemarkerlist[e]) {
3267           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3268           const PetscInt *edges;
3269           PetscInt        numEdges;
3270 
3271           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3272           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3273           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3274           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3275         }
3276       }
3277     }
3278     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3279   }
3280 #if 0 /* Do not currently support holes */
3281   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3282 #endif
3283   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3284   PetscFunctionReturn(0);
3285 }
3286 #endif
3287 
3288 #if defined(PETSC_HAVE_TETGEN)
3289 #include <tetgen.h>
3290 #undef __FUNCT__
3291 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3292 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3293 {
3294   MPI_Comm       comm;
3295   const PetscInt dim  = 3;
3296   ::tetgenio     in;
3297   ::tetgenio     out;
3298   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3299   PetscMPIInt    rank;
3300   PetscErrorCode ierr;
3301 
3302   PetscFunctionBegin;
3303   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3304   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3305   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3306   in.numberofpoints = vEnd - vStart;
3307   if (in.numberofpoints > 0) {
3308     PetscSection coordSection;
3309     Vec          coordinates;
3310     PetscScalar *array;
3311 
3312     in.pointlist       = new double[in.numberofpoints*dim];
3313     in.pointmarkerlist = new int[in.numberofpoints];
3314 
3315     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3316     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3317     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3318     for (v = vStart; v < vEnd; ++v) {
3319       const PetscInt idx = v - vStart;
3320       PetscInt       off, d;
3321 
3322       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3323       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3324       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3325     }
3326     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3327   }
3328   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3329 
3330   in.numberoffacets = fEnd - fStart;
3331   if (in.numberoffacets > 0) {
3332     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3333     in.facetmarkerlist = new int[in.numberoffacets];
3334     for (f = fStart; f < fEnd; ++f) {
3335       const PetscInt idx     = f - fStart;
3336       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3337 
3338       in.facetlist[idx].numberofpolygons = 1;
3339       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3340       in.facetlist[idx].numberofholes    = 0;
3341       in.facetlist[idx].holelist         = NULL;
3342 
3343       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3344       for (p = 0; p < numPoints*2; p += 2) {
3345         const PetscInt point = points[p];
3346         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3347       }
3348 
3349       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3350       poly->numberofvertices = numVertices;
3351       poly->vertexlist       = new int[poly->numberofvertices];
3352       for (v = 0; v < numVertices; ++v) {
3353         const PetscInt vIdx = points[v] - vStart;
3354         poly->vertexlist[v] = vIdx;
3355       }
3356       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3357       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3358     }
3359   }
3360   if (!rank) {
3361     char args[32];
3362 
3363     /* Take away 'Q' for verbose output */
3364     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3365     ::tetrahedralize(args, &in, &out);
3366   }
3367   {
3368     const PetscInt numCorners  = 4;
3369     const PetscInt numCells    = out.numberoftetrahedra;
3370     const PetscInt numVertices = out.numberofpoints;
3371     const int     *cells      = out.tetrahedronlist;
3372     const double  *meshCoords = out.pointlist;
3373 
3374     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3375     /* Set labels */
3376     for (v = 0; v < numVertices; ++v) {
3377       if (out.pointmarkerlist[v]) {
3378         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3379       }
3380     }
3381     if (interpolate) {
3382       PetscInt e;
3383 
3384       for (e = 0; e < out.numberofedges; e++) {
3385         if (out.edgemarkerlist[e]) {
3386           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3387           const PetscInt *edges;
3388           PetscInt        numEdges;
3389 
3390           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3391           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3392           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3393           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3394         }
3395       }
3396       for (f = 0; f < out.numberoftrifaces; f++) {
3397         if (out.trifacemarkerlist[f]) {
3398           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3399           const PetscInt *faces;
3400           PetscInt        numFaces;
3401 
3402           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3403           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3404           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3405           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3406         }
3407       }
3408     }
3409     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3410   }
3411   PetscFunctionReturn(0);
3412 }
3413 
3414 #undef __FUNCT__
3415 #define __FUNCT__ "DMPlexRefine_Tetgen"
3416 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3417 {
3418   MPI_Comm       comm;
3419   const PetscInt dim  = 3;
3420   ::tetgenio     in;
3421   ::tetgenio     out;
3422   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3423   PetscMPIInt    rank;
3424   PetscErrorCode ierr;
3425 
3426   PetscFunctionBegin;
3427   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3428   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3429   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3430   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3431   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3432 
3433   in.numberofpoints = vEnd - vStart;
3434   if (in.numberofpoints > 0) {
3435     PetscSection coordSection;
3436     Vec          coordinates;
3437     PetscScalar *array;
3438 
3439     in.pointlist       = new double[in.numberofpoints*dim];
3440     in.pointmarkerlist = new int[in.numberofpoints];
3441 
3442     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3443     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3444     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3445     for (v = vStart; v < vEnd; ++v) {
3446       const PetscInt idx = v - vStart;
3447       PetscInt       off, d;
3448 
3449       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3450       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3451       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3452     }
3453     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3454   }
3455   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3456 
3457   in.numberofcorners       = 4;
3458   in.numberoftetrahedra    = cEnd - cStart;
3459   in.tetrahedronvolumelist = (double*) maxVolumes;
3460   if (in.numberoftetrahedra > 0) {
3461     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3462     for (c = cStart; c < cEnd; ++c) {
3463       const PetscInt idx      = c - cStart;
3464       PetscInt      *closure = NULL;
3465       PetscInt       closureSize;
3466 
3467       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3468       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3469       for (v = 0; v < 4; ++v) {
3470         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3471       }
3472       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3473     }
3474   }
3475   /* TODO: Put in boundary faces with markers */
3476   if (!rank) {
3477     char args[32];
3478 
3479     /* Take away 'Q' for verbose output */
3480     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3481     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3482     ::tetrahedralize(args, &in, &out);
3483   }
3484   in.tetrahedronvolumelist = NULL;
3485 
3486   {
3487     const PetscInt numCorners  = 4;
3488     const PetscInt numCells    = out.numberoftetrahedra;
3489     const PetscInt numVertices = out.numberofpoints;
3490     const int     *cells      = out.tetrahedronlist;
3491     const double  *meshCoords = out.pointlist;
3492     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3493 
3494     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3495     /* Set labels */
3496     for (v = 0; v < numVertices; ++v) {
3497       if (out.pointmarkerlist[v]) {
3498         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3499       }
3500     }
3501     if (interpolate) {
3502       PetscInt e, f;
3503 
3504       for (e = 0; e < out.numberofedges; e++) {
3505         if (out.edgemarkerlist[e]) {
3506           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3507           const PetscInt *edges;
3508           PetscInt        numEdges;
3509 
3510           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3511           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3512           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3513           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3514         }
3515       }
3516       for (f = 0; f < out.numberoftrifaces; f++) {
3517         if (out.trifacemarkerlist[f]) {
3518           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3519           const PetscInt *faces;
3520           PetscInt        numFaces;
3521 
3522           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3523           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3524           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3525           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3526         }
3527       }
3528     }
3529     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3530   }
3531   PetscFunctionReturn(0);
3532 }
3533 #endif
3534 
3535 #if defined(PETSC_HAVE_CTETGEN)
3536 #include "ctetgen.h"
3537 
3538 #undef __FUNCT__
3539 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3540 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3541 {
3542   MPI_Comm       comm;
3543   const PetscInt dim  = 3;
3544   PLC           *in, *out;
3545   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3546   PetscMPIInt    rank;
3547   PetscErrorCode ierr;
3548 
3549   PetscFunctionBegin;
3550   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3551   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3552   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3553   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3554   ierr = PLCCreate(&in);CHKERRQ(ierr);
3555   ierr = PLCCreate(&out);CHKERRQ(ierr);
3556 
3557   in->numberofpoints = vEnd - vStart;
3558   if (in->numberofpoints > 0) {
3559     PetscSection coordSection;
3560     Vec          coordinates;
3561     PetscScalar *array;
3562 
3563     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3564     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3565     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3566     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3567     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3568     for (v = vStart; v < vEnd; ++v) {
3569       const PetscInt idx = v - vStart;
3570       PetscInt       off, d, m;
3571 
3572       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3573       for (d = 0; d < dim; ++d) {
3574         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3575       }
3576       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3577 
3578       in->pointmarkerlist[idx] = (int) m;
3579     }
3580     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3581   }
3582   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3583 
3584   in->numberoffacets = fEnd - fStart;
3585   if (in->numberoffacets > 0) {
3586     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
3587     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
3588     for (f = fStart; f < fEnd; ++f) {
3589       const PetscInt idx     = f - fStart;
3590       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3591       polygon       *poly;
3592 
3593       in->facetlist[idx].numberofpolygons = 1;
3594 
3595       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3596 
3597       in->facetlist[idx].numberofholes    = 0;
3598       in->facetlist[idx].holelist         = NULL;
3599 
3600       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3601       for (p = 0; p < numPoints*2; p += 2) {
3602         const PetscInt point = points[p];
3603         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3604       }
3605 
3606       poly                   = in->facetlist[idx].polygonlist;
3607       poly->numberofvertices = numVertices;
3608       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
3609       for (v = 0; v < numVertices; ++v) {
3610         const PetscInt vIdx = points[v] - vStart;
3611         poly->vertexlist[v] = vIdx;
3612       }
3613       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3614       in->facetmarkerlist[idx] = (int) m;
3615       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3616     }
3617   }
3618   if (!rank) {
3619     TetGenOpts t;
3620 
3621     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3622     t.in        = boundary; /* Should go away */
3623     t.plc       = 1;
3624     t.quality   = 1;
3625     t.edgesout  = 1;
3626     t.zeroindex = 1;
3627     t.quiet     = 1;
3628     t.verbose   = verbose;
3629     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3630     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3631   }
3632   {
3633     const PetscInt numCorners  = 4;
3634     const PetscInt numCells    = out->numberoftetrahedra;
3635     const PetscInt numVertices = out->numberofpoints;
3636     const int     *cells      = out->tetrahedronlist;
3637     const double  *meshCoords = out->pointlist;
3638 
3639     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3640     /* Set labels */
3641     for (v = 0; v < numVertices; ++v) {
3642       if (out->pointmarkerlist[v]) {
3643         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3644       }
3645     }
3646     if (interpolate) {
3647       PetscInt e;
3648 
3649       for (e = 0; e < out->numberofedges; e++) {
3650         if (out->edgemarkerlist[e]) {
3651           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3652           const PetscInt *edges;
3653           PetscInt        numEdges;
3654 
3655           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3656           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3657           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3658           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3659         }
3660       }
3661       for (f = 0; f < out->numberoftrifaces; f++) {
3662         if (out->trifacemarkerlist[f]) {
3663           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3664           const PetscInt *faces;
3665           PetscInt        numFaces;
3666 
3667           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3668           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3669           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3670           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3671         }
3672       }
3673     }
3674     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3675   }
3676 
3677   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3678   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3679   PetscFunctionReturn(0);
3680 }
3681 
3682 #undef __FUNCT__
3683 #define __FUNCT__ "DMPlexRefine_CTetgen"
3684 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3685 {
3686   MPI_Comm       comm;
3687   const PetscInt dim  = 3;
3688   PLC           *in, *out;
3689   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3690   PetscMPIInt    rank;
3691   PetscErrorCode ierr;
3692 
3693   PetscFunctionBegin;
3694   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3695   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3696   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3697   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3698   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3699   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3700   ierr = PLCCreate(&in);CHKERRQ(ierr);
3701   ierr = PLCCreate(&out);CHKERRQ(ierr);
3702 
3703   in->numberofpoints = vEnd - vStart;
3704   if (in->numberofpoints > 0) {
3705     PetscSection coordSection;
3706     Vec          coordinates;
3707     PetscScalar *array;
3708 
3709     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3710     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3711     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3712     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3713     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3714     for (v = vStart; v < vEnd; ++v) {
3715       const PetscInt idx = v - vStart;
3716       PetscInt       off, d, m;
3717 
3718       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3719       for (d = 0; d < dim; ++d) {
3720         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3721       }
3722       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
3723 
3724       in->pointmarkerlist[idx] = (int) m;
3725     }
3726     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3727   }
3728   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3729 
3730   in->numberofcorners       = 4;
3731   in->numberoftetrahedra    = cEnd - cStart;
3732   in->tetrahedronvolumelist = maxVolumes;
3733   if (in->numberoftetrahedra > 0) {
3734     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
3735     for (c = cStart; c < cEnd; ++c) {
3736       const PetscInt idx      = c - cStart;
3737       PetscInt      *closure = NULL;
3738       PetscInt       closureSize;
3739 
3740       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3741       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3742       for (v = 0; v < 4; ++v) {
3743         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3744       }
3745       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3746     }
3747   }
3748   if (!rank) {
3749     TetGenOpts t;
3750 
3751     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3752 
3753     t.in        = dm; /* Should go away */
3754     t.refine    = 1;
3755     t.varvolume = 1;
3756     t.quality   = 1;
3757     t.edgesout  = 1;
3758     t.zeroindex = 1;
3759     t.quiet     = 1;
3760     t.verbose   = verbose; /* Change this */
3761 
3762     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
3763     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3764   }
3765   {
3766     const PetscInt numCorners  = 4;
3767     const PetscInt numCells    = out->numberoftetrahedra;
3768     const PetscInt numVertices = out->numberofpoints;
3769     const int     *cells       = out->tetrahedronlist;
3770     const double  *meshCoords  = out->pointlist;
3771     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3772 
3773     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3774     /* Set labels */
3775     for (v = 0; v < numVertices; ++v) {
3776       if (out->pointmarkerlist[v]) {
3777         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3778       }
3779     }
3780     if (interpolate) {
3781       PetscInt e, f;
3782 
3783       for (e = 0; e < out->numberofedges; e++) {
3784         if (out->edgemarkerlist[e]) {
3785           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3786           const PetscInt *edges;
3787           PetscInt        numEdges;
3788 
3789           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3790           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3791           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3792           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3793         }
3794       }
3795       for (f = 0; f < out->numberoftrifaces; f++) {
3796         if (out->trifacemarkerlist[f]) {
3797           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3798           const PetscInt *faces;
3799           PetscInt        numFaces;
3800 
3801           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3802           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3803           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3804           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3805         }
3806       }
3807     }
3808     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3809   }
3810   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3811   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3812   PetscFunctionReturn(0);
3813 }
3814 #endif
3815 
3816 #undef __FUNCT__
3817 #define __FUNCT__ "DMPlexGenerate"
3818 /*@C
3819   DMPlexGenerate - Generates a mesh.
3820 
3821   Not Collective
3822 
3823   Input Parameters:
3824 + boundary - The DMPlex boundary object
3825 . name - The mesh generation package name
3826 - interpolate - Flag to create intermediate mesh elements
3827 
3828   Output Parameter:
3829 . mesh - The DMPlex object
3830 
3831   Level: intermediate
3832 
3833 .keywords: mesh, elements
3834 .seealso: DMPlexCreate(), DMRefine()
3835 @*/
3836 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
3837 {
3838   PetscInt       dim;
3839   char           genname[1024];
3840   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
3841   PetscErrorCode ierr;
3842 
3843   PetscFunctionBegin;
3844   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
3845   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
3846   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
3847   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
3848   if (flg) name = genname;
3849   if (name) {
3850     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
3851     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
3852     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
3853   }
3854   switch (dim) {
3855   case 1:
3856     if (!name || isTriangle) {
3857 #if defined(PETSC_HAVE_TRIANGLE)
3858       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
3859 #else
3860       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
3861 #endif
3862     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
3863     break;
3864   case 2:
3865     if (!name || isCTetgen) {
3866 #if defined(PETSC_HAVE_CTETGEN)
3867       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
3868 #else
3869       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
3870 #endif
3871     } else if (isTetgen) {
3872 #if defined(PETSC_HAVE_TETGEN)
3873       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
3874 #else
3875       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
3876 #endif
3877     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
3878     break;
3879   default:
3880     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
3881   }
3882   PetscFunctionReturn(0);
3883 }
3884 
3885 typedef PetscInt CellRefiner;
3886 
3887 #undef __FUNCT__
3888 #define __FUNCT__ "GetDepthStart_Private"
3889 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
3890 {
3891   PetscFunctionBegin;
3892   if (cStart) *cStart = 0;
3893   if (vStart) *vStart = depthSize[depth];
3894   if (fStart) *fStart = depthSize[depth] + depthSize[0];
3895   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
3896   PetscFunctionReturn(0);
3897 }
3898 
3899 #undef __FUNCT__
3900 #define __FUNCT__ "GetDepthEnd_Private"
3901 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
3902 {
3903   PetscFunctionBegin;
3904   if (cEnd) *cEnd = depthSize[depth];
3905   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
3906   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
3907   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
3908   PetscFunctionReturn(0);
3909 }
3910 
3911 #undef __FUNCT__
3912 #define __FUNCT__ "CellRefinerGetSizes"
3913 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
3914 {
3915   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
3916   PetscErrorCode ierr;
3917 
3918   PetscFunctionBegin;
3919   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3920   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3921   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3922   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3923   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3924   switch (refiner) {
3925   case 1:
3926     /* Simplicial 2D */
3927     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
3928     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
3929     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
3930     break;
3931   case 3:
3932     /* Hybrid 2D */
3933     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3934     cMax = PetscMin(cEnd, cMax);
3935     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3936     fMax         = PetscMin(fEnd, fMax);
3937     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
3938     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
3939     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
3940     break;
3941   case 2:
3942     /* Hex 2D */
3943     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
3944     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
3945     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
3946     break;
3947   default:
3948     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3949   }
3950   PetscFunctionReturn(0);
3951 }
3952 
3953 #undef __FUNCT__
3954 #define __FUNCT__ "CellRefinerSetConeSizes"
3955 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3956 {
3957   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
3958   PetscErrorCode ierr;
3959 
3960   PetscFunctionBegin;
3961   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3962   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3963   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3964   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3965   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3966   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3967   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
3968   switch (refiner) {
3969   case 1:
3970     /* Simplicial 2D */
3971     /* All cells have 3 faces */
3972     for (c = cStart; c < cEnd; ++c) {
3973       for (r = 0; r < 4; ++r) {
3974         const PetscInt newp = (c - cStart)*4 + r;
3975 
3976         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
3977       }
3978     }
3979     /* Split faces have 2 vertices and the same cells as the parent */
3980     for (f = fStart; f < fEnd; ++f) {
3981       for (r = 0; r < 2; ++r) {
3982         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
3983         PetscInt       size;
3984 
3985         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
3986         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
3987         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
3988       }
3989     }
3990     /* Interior faces have 2 vertices and 2 cells */
3991     for (c = cStart; c < cEnd; ++c) {
3992       for (r = 0; r < 3; ++r) {
3993         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
3994 
3995         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
3996         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
3997       }
3998     }
3999     /* Old vertices have identical supports */
4000     for (v = vStart; v < vEnd; ++v) {
4001       const PetscInt newp = vStartNew + (v - vStart);
4002       PetscInt       size;
4003 
4004       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4005       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4006     }
4007     /* Face vertices have 2 + cells*2 supports */
4008     for (f = fStart; f < fEnd; ++f) {
4009       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4010       PetscInt       size;
4011 
4012       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4013       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
4014     }
4015     break;
4016   case 2:
4017     /* Hex 2D */
4018     /* All cells have 4 faces */
4019     for (c = cStart; c < cEnd; ++c) {
4020       for (r = 0; r < 4; ++r) {
4021         const PetscInt newp = (c - cStart)*4 + r;
4022 
4023         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4024       }
4025     }
4026     /* Split faces have 2 vertices and the same cells as the parent */
4027     for (f = fStart; f < fEnd; ++f) {
4028       for (r = 0; r < 2; ++r) {
4029         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4030         PetscInt       size;
4031 
4032         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4033         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4034         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4035       }
4036     }
4037     /* Interior faces have 2 vertices and 2 cells */
4038     for (c = cStart; c < cEnd; ++c) {
4039       for (r = 0; r < 4; ++r) {
4040         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4041 
4042         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4043         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4044       }
4045     }
4046     /* Old vertices have identical supports */
4047     for (v = vStart; v < vEnd; ++v) {
4048       const PetscInt newp = vStartNew + (v - vStart);
4049       PetscInt       size;
4050 
4051       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4052       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4053     }
4054     /* Face vertices have 2 + cells supports */
4055     for (f = fStart; f < fEnd; ++f) {
4056       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4057       PetscInt       size;
4058 
4059       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4060       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
4061     }
4062     /* Cell vertices have 4 supports */
4063     for (c = cStart; c < cEnd; ++c) {
4064       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4065 
4066       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
4067     }
4068     break;
4069   case 3:
4070     /* Hybrid 2D */
4071     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4072     cMax = PetscMin(cEnd, cMax);
4073     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4074     fMax = PetscMin(fEnd, fMax);
4075     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4076     /* Interior cells have 3 faces */
4077     for (c = cStart; c < cMax; ++c) {
4078       for (r = 0; r < 4; ++r) {
4079         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
4080 
4081         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4082       }
4083     }
4084     /* Hybrid cells have 4 faces */
4085     for (c = cMax; c < cEnd; ++c) {
4086       for (r = 0; r < 2; ++r) {
4087         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
4088 
4089         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4090       }
4091     }
4092     /* Interior split faces have 2 vertices and the same cells as the parent */
4093     for (f = fStart; f < fMax; ++f) {
4094       for (r = 0; r < 2; ++r) {
4095         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4096         PetscInt       size;
4097 
4098         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4099         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4100         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4101       }
4102     }
4103     /* Interior cell faces have 2 vertices and 2 cells */
4104     for (c = cStart; c < cMax; ++c) {
4105       for (r = 0; r < 3; ++r) {
4106         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4107 
4108         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4109         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4110       }
4111     }
4112     /* Hybrid faces have 2 vertices and the same cells */
4113     for (f = fMax; f < fEnd; ++f) {
4114       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4115       PetscInt       size;
4116 
4117       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4118       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4119       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4120     }
4121     /* Hybrid cell faces have 2 vertices and 2 cells */
4122     for (c = cMax; c < cEnd; ++c) {
4123       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4124 
4125       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4126       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4127     }
4128     /* Old vertices have identical supports */
4129     for (v = vStart; v < vEnd; ++v) {
4130       const PetscInt newp = vStartNew + (v - vStart);
4131       PetscInt       size;
4132 
4133       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4134       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4135     }
4136     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4137     for (f = fStart; f < fMax; ++f) {
4138       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4139       const PetscInt *support;
4140       PetscInt       size, newSize = 2, s;
4141 
4142       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4143       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4144       for (s = 0; s < size; ++s) {
4145         if (support[s] >= cMax) newSize += 1;
4146         else newSize += 2;
4147       }
4148       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
4149     }
4150     break;
4151   default:
4152     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4153   }
4154   PetscFunctionReturn(0);
4155 }
4156 
4157 #undef __FUNCT__
4158 #define __FUNCT__ "CellRefinerSetCones"
4159 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4160 {
4161   PetscInt       depth, cStart, cEnd, cMax, cStartNew, cEndNew, c, vStart, vEnd, vMax, vStartNew, vEndNew, v, fStart, fEnd, fMax, fStartNew, fEndNew, f, eStart, eEnd, eMax, eStartNew, eEndNew, r, p;
4162   PetscInt       maxSupportSize, *supportRef;
4163   PetscErrorCode ierr;
4164 
4165   PetscFunctionBegin;
4166   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4167   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4168   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4169   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4170   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4171   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4172   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4173   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
4174   switch (refiner) {
4175   case 1:
4176     /* Simplicial 2D */
4177     /*
4178      2
4179      |\
4180      | \
4181      |  \
4182      |   \
4183      | C  \
4184      |     \
4185      |      \
4186      2---1---1
4187      |\  D  / \
4188      | 2   0   \
4189      |A \ /  B  \
4190      0---0-------1
4191      */
4192     /* All cells have 3 faces */
4193     for (c = cStart; c < cEnd; ++c) {
4194       const PetscInt  newp = cStartNew + (c - cStart)*4;
4195       const PetscInt *cone, *ornt;
4196       PetscInt        coneNew[3], orntNew[3];
4197 
4198       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4199       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4200       /* A triangle */
4201       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4202       orntNew[0] = ornt[0];
4203       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4204       orntNew[1] = -2;
4205       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4206       orntNew[2] = ornt[2];
4207       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4208       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4209 #if 1
4210       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4211       for (p = 0; p < 3; ++p) {
4212         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4213       }
4214 #endif
4215       /* B triangle */
4216       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4217       orntNew[0] = ornt[0];
4218       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4219       orntNew[1] = ornt[1];
4220       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4221       orntNew[2] = -2;
4222       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4223       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4224 #if 1
4225       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4226       for (p = 0; p < 3; ++p) {
4227         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4228       }
4229 #endif
4230       /* C triangle */
4231       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4232       orntNew[0] = -2;
4233       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4234       orntNew[1] = ornt[1];
4235       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4236       orntNew[2] = ornt[2];
4237       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4238       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4239 #if 1
4240       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4241       for (p = 0; p < 3; ++p) {
4242         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4243       }
4244 #endif
4245       /* D triangle */
4246       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4247       orntNew[0] = 0;
4248       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4249       orntNew[1] = 0;
4250       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4251       orntNew[2] = 0;
4252       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4253       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4254 #if 1
4255       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4256       for (p = 0; p < 3; ++p) {
4257         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4258       }
4259 #endif
4260     }
4261     /* Split faces have 2 vertices and the same cells as the parent */
4262     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4263     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4264     for (f = fStart; f < fEnd; ++f) {
4265       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4266 
4267       for (r = 0; r < 2; ++r) {
4268         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4269         const PetscInt *cone, *support;
4270         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4271 
4272         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4273         coneNew[0]       = vStartNew + (cone[0] - vStart);
4274         coneNew[1]       = vStartNew + (cone[1] - vStart);
4275         coneNew[(r+1)%2] = newv;
4276         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4277 #if 1
4278         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4279         for (p = 0; p < 2; ++p) {
4280           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4281         }
4282 #endif
4283         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4284         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4285         for (s = 0; s < supportSize; ++s) {
4286           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4287           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4288           for (c = 0; c < coneSize; ++c) {
4289             if (cone[c] == f) break;
4290           }
4291           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4292         }
4293         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4294 #if 1
4295         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4296         for (p = 0; p < supportSize; ++p) {
4297           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4298         }
4299 #endif
4300       }
4301     }
4302     /* Interior faces have 2 vertices and 2 cells */
4303     for (c = cStart; c < cEnd; ++c) {
4304       const PetscInt *cone;
4305 
4306       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4307       for (r = 0; r < 3; ++r) {
4308         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4309         PetscInt       coneNew[2];
4310         PetscInt       supportNew[2];
4311 
4312         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4313         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4314         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4315 #if 1
4316         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4317         for (p = 0; p < 2; ++p) {
4318           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4319         }
4320 #endif
4321         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4322         supportNew[1] = (c - cStart)*4 + 3;
4323         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4324 #if 1
4325         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4326         for (p = 0; p < 2; ++p) {
4327           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4328         }
4329 #endif
4330       }
4331     }
4332     /* Old vertices have identical supports */
4333     for (v = vStart; v < vEnd; ++v) {
4334       const PetscInt  newp = vStartNew + (v - vStart);
4335       const PetscInt *support, *cone;
4336       PetscInt        size, s;
4337 
4338       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4339       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4340       for (s = 0; s < size; ++s) {
4341         PetscInt r = 0;
4342 
4343         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4344         if (cone[1] == v) r = 1;
4345         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4346       }
4347       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4348 #if 1
4349       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4350       for (p = 0; p < size; ++p) {
4351         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4352       }
4353 #endif
4354     }
4355     /* Face vertices have 2 + cells*2 supports */
4356     for (f = fStart; f < fEnd; ++f) {
4357       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4358       const PetscInt *cone, *support;
4359       PetscInt        size, s;
4360 
4361       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4362       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4363       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4364       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4365       for (s = 0; s < size; ++s) {
4366         PetscInt r = 0;
4367 
4368         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4369         if      (cone[1] == f) r = 1;
4370         else if (cone[2] == f) r = 2;
4371         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4372         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4373       }
4374       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4375 #if 1
4376       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4377       for (p = 0; p < 2+size*2; ++p) {
4378         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4379       }
4380 #endif
4381     }
4382     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4383     break;
4384   case 2:
4385     /* Hex 2D */
4386     /*
4387      3---------2---------2
4388      |         |         |
4389      |    D    2    C    |
4390      |         |         |
4391      3----3----0----1----1
4392      |         |         |
4393      |    A    0    B    |
4394      |         |         |
4395      0---------0---------1
4396      */
4397     /* All cells have 4 faces */
4398     for (c = cStart; c < cEnd; ++c) {
4399       const PetscInt  newp = (c - cStart)*4;
4400       const PetscInt *cone, *ornt;
4401       PetscInt        coneNew[4], orntNew[4];
4402 
4403       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4404       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4405       /* A quad */
4406       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4407       orntNew[0] = ornt[0];
4408       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4409       orntNew[1] = 0;
4410       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4411       orntNew[2] = -2;
4412       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4413       orntNew[3] = ornt[3];
4414       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4415       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4416 #if 1
4417       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4418       for (p = 0; p < 4; ++p) {
4419         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4420       }
4421 #endif
4422       /* B quad */
4423       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4424       orntNew[0] = ornt[0];
4425       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4426       orntNew[1] = ornt[1];
4427       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4428       orntNew[2] = 0;
4429       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4430       orntNew[3] = -2;
4431       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4432       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4433 #if 1
4434       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4435       for (p = 0; p < 4; ++p) {
4436         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4437       }
4438 #endif
4439       /* C quad */
4440       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4441       orntNew[0] = -2;
4442       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4443       orntNew[1] = ornt[1];
4444       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4445       orntNew[2] = ornt[2];
4446       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4447       orntNew[3] = 0;
4448       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4449       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4450 #if 1
4451       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4452       for (p = 0; p < 4; ++p) {
4453         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4454       }
4455 #endif
4456       /* D quad */
4457       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4458       orntNew[0] = 0;
4459       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4460       orntNew[1] = -2;
4461       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4462       orntNew[2] = ornt[2];
4463       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
4464       orntNew[3] = ornt[3];
4465       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4466       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4467 #if 1
4468       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4469       for (p = 0; p < 4; ++p) {
4470         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4471       }
4472 #endif
4473     }
4474     /* Split faces have 2 vertices and the same cells as the parent */
4475     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4476     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4477     for (f = fStart; f < fEnd; ++f) {
4478       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4479 
4480       for (r = 0; r < 2; ++r) {
4481         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4482         const PetscInt *cone, *support;
4483         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4484 
4485         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4486         coneNew[0]       = vStartNew + (cone[0] - vStart);
4487         coneNew[1]       = vStartNew + (cone[1] - vStart);
4488         coneNew[(r+1)%2] = newv;
4489         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4490 #if 1
4491         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4492         for (p = 0; p < 2; ++p) {
4493           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4494         }
4495 #endif
4496         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4497         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4498         for (s = 0; s < supportSize; ++s) {
4499           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4500           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4501           for (c = 0; c < coneSize; ++c) {
4502             if (cone[c] == f) break;
4503           }
4504           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
4505         }
4506         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4507 #if 1
4508         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4509         for (p = 0; p < supportSize; ++p) {
4510           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4511         }
4512 #endif
4513       }
4514     }
4515     /* Interior faces have 2 vertices and 2 cells */
4516     for (c = cStart; c < cEnd; ++c) {
4517       const PetscInt *cone;
4518       PetscInt        coneNew[2], supportNew[2];
4519 
4520       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4521       for (r = 0; r < 4; ++r) {
4522         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4523 
4524         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
4525         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
4526         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4527 #if 1
4528         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4529         for (p = 0; p < 2; ++p) {
4530           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4531         }
4532 #endif
4533         supportNew[0] = (c - cStart)*4 + r;
4534         supportNew[1] = (c - cStart)*4 + (r+1)%4;
4535         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4536 #if 1
4537         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4538         for (p = 0; p < 2; ++p) {
4539           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4540         }
4541 #endif
4542       }
4543     }
4544     /* Old vertices have identical supports */
4545     for (v = vStart; v < vEnd; ++v) {
4546       const PetscInt  newp = vStartNew + (v - vStart);
4547       const PetscInt *support, *cone;
4548       PetscInt        size, s;
4549 
4550       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4551       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4552       for (s = 0; s < size; ++s) {
4553         PetscInt r = 0;
4554 
4555         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4556         if (cone[1] == v) r = 1;
4557         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4558       }
4559       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4560 #if 1
4561       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4562       for (p = 0; p < size; ++p) {
4563         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4564       }
4565 #endif
4566     }
4567     /* Face vertices have 2 + cells supports */
4568     for (f = fStart; f < fEnd; ++f) {
4569       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4570       const PetscInt *cone, *support;
4571       PetscInt        size, s;
4572 
4573       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4574       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4575       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4576       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4577       for (s = 0; s < size; ++s) {
4578         PetscInt r = 0;
4579 
4580         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4581         if      (cone[1] == f) r = 1;
4582         else if (cone[2] == f) r = 2;
4583         else if (cone[3] == f) r = 3;
4584         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
4585       }
4586       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4587 #if 1
4588       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4589       for (p = 0; p < 2+size; ++p) {
4590         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4591       }
4592 #endif
4593     }
4594     /* Cell vertices have 4 supports */
4595     for (c = cStart; c < cEnd; ++c) {
4596       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4597       PetscInt       supportNew[4];
4598 
4599       for (r = 0; r < 4; ++r) {
4600         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4601       }
4602       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4603     }
4604     break;
4605   case 3:
4606     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4607     cMax = PetscMin(cEnd, cMax);
4608     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4609     fMax = PetscMin(fEnd, fMax);
4610     /* Interior cells have 3 faces */
4611     for (c = cStart; c < cMax; ++c) {
4612       const PetscInt  newp = cStartNew + (c - cStart)*4;
4613       const PetscInt *cone, *ornt;
4614       PetscInt        coneNew[3], orntNew[3];
4615 
4616       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4617       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4618       /* A triangle */
4619       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4620       orntNew[0] = ornt[0];
4621       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4622       orntNew[1] = -2;
4623       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4624       orntNew[2] = ornt[2];
4625       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4626       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4627 #if 1
4628       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4629       for (p = 0; p < 3; ++p) {
4630         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4631       }
4632 #endif
4633       /* B triangle */
4634       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4635       orntNew[0] = ornt[0];
4636       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4637       orntNew[1] = ornt[1];
4638       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4639       orntNew[2] = -2;
4640       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4641       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4642 #if 1
4643       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4644       for (p = 0; p < 3; ++p) {
4645         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4646       }
4647 #endif
4648       /* C triangle */
4649       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4650       orntNew[0] = -2;
4651       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4652       orntNew[1] = ornt[1];
4653       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4654       orntNew[2] = ornt[2];
4655       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4656       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4657 #if 1
4658       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
4659       for (p = 0; p < 3; ++p) {
4660         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4661       }
4662 #endif
4663       /* D triangle */
4664       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4665       orntNew[0] = 0;
4666       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4667       orntNew[1] = 0;
4668       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4669       orntNew[2] = 0;
4670       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4671       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4672 #if 1
4673       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
4674       for (p = 0; p < 3; ++p) {
4675         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4676       }
4677 #endif
4678     }
4679     /*
4680      2----3----3
4681      |         |
4682      |    B    |
4683      |         |
4684      0----4--- 1
4685      |         |
4686      |    A    |
4687      |         |
4688      0----2----1
4689      */
4690     /* Hybrid cells have 4 faces */
4691     for (c = cMax; c < cEnd; ++c) {
4692       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
4693       const PetscInt *cone, *ornt;
4694       PetscInt        coneNew[4], orntNew[4];
4695 
4696       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4697       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4698       /* A quad */
4699       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4700       orntNew[0] = ornt[0];
4701       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4702       orntNew[1] = ornt[1];
4703       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
4704       orntNew[2] = 0;
4705       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4706       orntNew[3] = 0;
4707       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4708       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4709 #if 1
4710       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
4711       for (p = 0; p < 4; ++p) {
4712         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4713       }
4714 #endif
4715       /* B quad */
4716       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4717       orntNew[0] = ornt[0];
4718       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4719       orntNew[1] = ornt[1];
4720       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4721       orntNew[2] = 0;
4722       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
4723       orntNew[3] = 0;
4724       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4725       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4726 #if 1
4727       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
4728       for (p = 0; p < 4; ++p) {
4729         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
4730       }
4731 #endif
4732     }
4733     /* Interior split faces have 2 vertices and the same cells as the parent */
4734     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4735     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4736     for (f = fStart; f < fMax; ++f) {
4737       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4738 
4739       for (r = 0; r < 2; ++r) {
4740         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4741         const PetscInt *cone, *support;
4742         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4743 
4744         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4745         coneNew[0]       = vStartNew + (cone[0] - vStart);
4746         coneNew[1]       = vStartNew + (cone[1] - vStart);
4747         coneNew[(r+1)%2] = newv;
4748         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4749 #if 1
4750         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4751         for (p = 0; p < 2; ++p) {
4752           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4753         }
4754 #endif
4755         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4756         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4757         for (s = 0; s < supportSize; ++s) {
4758           if (support[s] >= cMax) {
4759             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4760           } else {
4761             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4762             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4763             for (c = 0; c < coneSize; ++c) {
4764               if (cone[c] == f) break;
4765             }
4766             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4767           }
4768         }
4769         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4770 #if 1
4771         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4772         for (p = 0; p < supportSize; ++p) {
4773           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
4774         }
4775 #endif
4776       }
4777     }
4778     /* Interior cell faces have 2 vertices and 2 cells */
4779     for (c = cStart; c < cMax; ++c) {
4780       const PetscInt *cone;
4781 
4782       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4783       for (r = 0; r < 3; ++r) {
4784         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4785         PetscInt       coneNew[2];
4786         PetscInt       supportNew[2];
4787 
4788         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4789         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4790         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4791 #if 1
4792         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4793         for (p = 0; p < 2; ++p) {
4794           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4795         }
4796 #endif
4797         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4798         supportNew[1] = (c - cStart)*4 + 3;
4799         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4800 #if 1
4801         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4802         for (p = 0; p < 2; ++p) {
4803           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4804         }
4805 #endif
4806       }
4807     }
4808     /* Interior hybrid faces have 2 vertices and the same cells */
4809     for (f = fMax; f < fEnd; ++f) {
4810       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4811       const PetscInt *cone;
4812       const PetscInt *support;
4813       PetscInt        coneNew[2];
4814       PetscInt        supportNew[2];
4815       PetscInt        size, s, r;
4816 
4817       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4818       coneNew[0] = vStartNew + (cone[0] - vStart);
4819       coneNew[1] = vStartNew + (cone[1] - vStart);
4820       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4821 #if 1
4822       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4823       for (p = 0; p < 2; ++p) {
4824         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4825       }
4826 #endif
4827       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4828       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4829       for (s = 0; s < size; ++s) {
4830         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4831         for (r = 0; r < 2; ++r) {
4832           if (cone[r+2] == f) break;
4833         }
4834         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4835       }
4836       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4837 #if 1
4838       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4839       for (p = 0; p < size; ++p) {
4840         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4841       }
4842 #endif
4843     }
4844     /* Cell hybrid faces have 2 vertices and 2 cells */
4845     for (c = cMax; c < cEnd; ++c) {
4846       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4847       const PetscInt *cone;
4848       PetscInt        coneNew[2];
4849       PetscInt        supportNew[2];
4850 
4851       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4852       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
4853       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
4854       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4855 #if 1
4856       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4857       for (p = 0; p < 2; ++p) {
4858         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
4859       }
4860 #endif
4861       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
4862       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
4863       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4864 #if 1
4865       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4866       for (p = 0; p < 2; ++p) {
4867         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
4868       }
4869 #endif
4870     }
4871     /* Old vertices have identical supports */
4872     for (v = vStart; v < vEnd; ++v) {
4873       const PetscInt  newp = vStartNew + (v - vStart);
4874       const PetscInt *support, *cone;
4875       PetscInt        size, s;
4876 
4877       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4878       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4879       for (s = 0; s < size; ++s) {
4880         if (support[s] >= fMax) {
4881           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
4882         } else {
4883           PetscInt r = 0;
4884 
4885           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4886           if (cone[1] == v) r = 1;
4887           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4888         }
4889       }
4890       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4891 #if 1
4892       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4893       for (p = 0; p < size; ++p) {
4894         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4895       }
4896 #endif
4897     }
4898     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4899     for (f = fStart; f < fMax; ++f) {
4900       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4901       const PetscInt *cone, *support;
4902       PetscInt        size, newSize = 2, s;
4903 
4904       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4905       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4906       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4907       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4908       for (s = 0; s < size; ++s) {
4909         PetscInt r = 0;
4910 
4911         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4912         if (support[s] >= cMax) {
4913           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
4914 
4915           newSize += 1;
4916         } else {
4917           if      (cone[1] == f) r = 1;
4918           else if (cone[2] == f) r = 2;
4919           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4920           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
4921 
4922           newSize += 2;
4923         }
4924       }
4925       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4926 #if 1
4927       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4928       for (p = 0; p < newSize; ++p) {
4929         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4930       }
4931 #endif
4932     }
4933     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4934     break;
4935   default:
4936     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4937   }
4938   PetscFunctionReturn(0);
4939 }
4940 
4941 #undef __FUNCT__
4942 #define __FUNCT__ "CellRefinerSetCoordinates"
4943 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4944 {
4945   PetscSection   coordSection, coordSectionNew;
4946   Vec            coordinates, coordinatesNew;
4947   PetscScalar   *coords, *coordsNew;
4948   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
4949   PetscErrorCode ierr;
4950 
4951   PetscFunctionBegin;
4952   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4953   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4954   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4955   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4956   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4957   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
4958   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
4959   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4960   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
4961   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
4962   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
4963   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
4964   if (fMax < 0) fMax = fEnd;
4965   switch (refiner) {
4966   case 1:
4967   case 2:
4968   case 3:
4969     /* Simplicial and Hex 2D */
4970     /* All vertices have the dim coordinates */
4971     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
4972       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
4973       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
4974     }
4975     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
4976     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
4977     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4978     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
4979     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
4980     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
4981     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
4982     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
4983     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4984     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
4985     /* Old vertices have the same coordinates */
4986     for (v = vStart; v < vEnd; ++v) {
4987       const PetscInt newv = vStartNew + (v - vStart);
4988       PetscInt       off, offnew, d;
4989 
4990       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4991       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
4992       for (d = 0; d < dim; ++d) {
4993         coordsNew[offnew+d] = coords[off+d];
4994       }
4995     }
4996     /* Face vertices have the average of endpoint coordinates */
4997     for (f = fStart; f < fMax; ++f) {
4998       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
4999       const PetscInt *cone;
5000       PetscInt        coneSize, offA, offB, offnew, d;
5001 
5002       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5003       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5004       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5005       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5006       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5007       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5008       for (d = 0; d < dim; ++d) {
5009         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5010       }
5011     }
5012     /* Just Hex 2D */
5013     if (refiner == 2) {
5014       /* Cell vertices have the average of corner coordinates */
5015       for (c = cStart; c < cEnd; ++c) {
5016         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5017         PetscInt      *cone = NULL;
5018         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5019 
5020         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5021         for (p = 0; p < closureSize*2; p += 2) {
5022           const PetscInt point = cone[p];
5023           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5024         }
5025         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5026         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5027         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5028         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5029         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5030         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5031         for (d = 0; d < dim; ++d) {
5032           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5033         }
5034         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5035       }
5036     }
5037     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5038     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5039     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5040     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5041     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5042     break;
5043   default:
5044     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5045   }
5046   PetscFunctionReturn(0);
5047 }
5048 
5049 #undef __FUNCT__
5050 #define __FUNCT__ "DMPlexCreateProcessSF"
5051 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5052 {
5053   PetscInt           numRoots, numLeaves, l;
5054   const PetscInt    *localPoints;
5055   const PetscSFNode *remotePoints;
5056   PetscInt          *localPointsNew;
5057   PetscSFNode       *remotePointsNew;
5058   PetscInt          *ranks, *ranksNew;
5059   PetscErrorCode     ierr;
5060 
5061   PetscFunctionBegin;
5062   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5063   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5064   for (l = 0; l < numLeaves; ++l) {
5065     ranks[l] = remotePoints[l].rank;
5066   }
5067   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5068   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
5069   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5070   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5071   for (l = 0; l < numLeaves; ++l) {
5072     ranksNew[l]              = ranks[l];
5073     localPointsNew[l]        = l;
5074     remotePointsNew[l].index = 0;
5075     remotePointsNew[l].rank  = ranksNew[l];
5076   }
5077   ierr = PetscFree(ranks);CHKERRQ(ierr);
5078   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5079   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5080   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5081   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5082   PetscFunctionReturn(0);
5083 }
5084 
5085 #undef __FUNCT__
5086 #define __FUNCT__ "CellRefinerCreateSF"
5087 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5088 {
5089   PetscSF            sf, sfNew, sfProcess;
5090   IS                 processRanks;
5091   MPI_Datatype       depthType;
5092   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5093   const PetscInt    *localPoints, *neighbors;
5094   const PetscSFNode *remotePoints;
5095   PetscInt          *localPointsNew;
5096   PetscSFNode       *remotePointsNew;
5097   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5098   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5099   PetscErrorCode     ierr;
5100 
5101   PetscFunctionBegin;
5102   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5103   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5104   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5105   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5106   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5107   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5108   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5109   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5110   switch (refiner) {
5111   case 3:
5112     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5113     cMax = PetscMin(cEnd, cMax);
5114     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5115     fMax = PetscMin(fEnd, fMax);
5116   }
5117   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5118   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5119   /* Caculate size of new SF */
5120   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5121   if (numRoots < 0) PetscFunctionReturn(0);
5122   for (l = 0; l < numLeaves; ++l) {
5123     const PetscInt p = localPoints[l];
5124 
5125     switch (refiner) {
5126     case 1:
5127       /* Simplicial 2D */
5128       if ((p >= vStart) && (p < vEnd)) {
5129         /* Old vertices stay the same */
5130         ++numLeavesNew;
5131       } else if ((p >= fStart) && (p < fEnd)) {
5132         /* Old faces add new faces and vertex */
5133         numLeavesNew += 1 + 2;
5134       } else if ((p >= cStart) && (p < cEnd)) {
5135         /* Old cells add new cells and interior faces */
5136         numLeavesNew += 4 + 3;
5137       }
5138       break;
5139     case 2:
5140       /* Hex 2D */
5141       if ((p >= vStart) && (p < vEnd)) {
5142         /* Old vertices stay the same */
5143         ++numLeavesNew;
5144       } else if ((p >= fStart) && (p < fEnd)) {
5145         /* Old faces add new faces and vertex */
5146         numLeavesNew += 1 + 2;
5147       } else if ((p >= cStart) && (p < cEnd)) {
5148         /* Old cells add new cells and interior faces */
5149         numLeavesNew += 4 + 4;
5150       }
5151       break;
5152     default:
5153       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5154     }
5155   }
5156   /* Communicate depthSizes for each remote rank */
5157   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5158   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5159   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
5160   ierr = PetscMalloc7(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthMaxOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);CHKERRQ(ierr);
5161   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5162   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5163   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5164   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5165   for (n = 0; n < numNeighbors; ++n) {
5166     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5167   }
5168   depthSizeOld[depth]   = cMax;
5169   depthSizeOld[0]       = vMax;
5170   depthSizeOld[depth-1] = fMax;
5171   depthSizeOld[1]       = eMax;
5172 
5173   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5174   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5175 
5176   depthSizeOld[depth]   = cEnd - cStart;
5177   depthSizeOld[0]       = vEnd - vStart;
5178   depthSizeOld[depth-1] = fEnd - fStart;
5179   depthSizeOld[1]       = eEnd - eStart;
5180 
5181   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5182   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5183   for (n = 0; n < numNeighbors; ++n) {
5184     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5185   }
5186   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5187   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5188   /* Calculate new point SF */
5189   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5190   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5191   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5192   for (l = 0, m = 0; l < numLeaves; ++l) {
5193     PetscInt    p     = localPoints[l];
5194     PetscInt    rp    = remotePoints[l].index, n;
5195     PetscMPIInt rrank = remotePoints[l].rank;
5196 
5197     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5198     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5199     switch (refiner) {
5200     case 1:
5201       /* Simplicial 2D */
5202       if ((p >= vStart) && (p < vEnd)) {
5203         /* Old vertices stay the same */
5204         localPointsNew[m]        = vStartNew     + (p  - vStart);
5205         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5206         remotePointsNew[m].rank  = rrank;
5207         ++m;
5208       } else if ((p >= fStart) && (p < fEnd)) {
5209         /* Old faces add new faces and vertex */
5210         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5211         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5212         remotePointsNew[m].rank  = rrank;
5213         ++m;
5214         for (r = 0; r < 2; ++r, ++m) {
5215           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5216           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5217           remotePointsNew[m].rank  = rrank;
5218         }
5219       } else if ((p >= cStart) && (p < cEnd)) {
5220         /* Old cells add new cells and interior faces */
5221         for (r = 0; r < 4; ++r, ++m) {
5222           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5223           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5224           remotePointsNew[m].rank  = rrank;
5225         }
5226         for (r = 0; r < 3; ++r, ++m) {
5227           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5228           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5229           remotePointsNew[m].rank  = rrank;
5230         }
5231       }
5232       break;
5233     case 2:
5234       /* Hex 2D */
5235       if ((p >= vStart) && (p < vEnd)) {
5236         /* Old vertices stay the same */
5237         localPointsNew[m]        = vStartNew     + (p  - vStart);
5238         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5239         remotePointsNew[m].rank  = rrank;
5240         ++m;
5241       } else if ((p >= fStart) && (p < fEnd)) {
5242         /* Old faces add new faces and vertex */
5243         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5244         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5245         remotePointsNew[m].rank  = rrank;
5246         ++m;
5247         for (r = 0; r < 2; ++r, ++m) {
5248           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5249           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5250           remotePointsNew[m].rank  = rrank;
5251         }
5252       } else if ((p >= cStart) && (p < cEnd)) {
5253         /* Old cells add new cells and interior faces */
5254         for (r = 0; r < 4; ++r, ++m) {
5255           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5256           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5257           remotePointsNew[m].rank  = rrank;
5258         }
5259         for (r = 0; r < 4; ++r, ++m) {
5260           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5261           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5262           remotePointsNew[m].rank  = rrank;
5263         }
5264       }
5265       break;
5266     case 3:
5267       /* Hybrid simplicial 2D */
5268       if ((p >= vStart) && (p < vEnd)) {
5269         /* Old vertices stay the same */
5270         localPointsNew[m]        = vStartNew     + (p  - vStart);
5271         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5272         remotePointsNew[m].rank  = rrank;
5273         ++m;
5274       } else if ((p >= fStart) && (p < fMax)) {
5275         /* Old interior faces add new faces and vertex */
5276         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5277         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5278         remotePointsNew[m].rank  = rrank;
5279         ++m;
5280         for (r = 0; r < 2; ++r, ++m) {
5281           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5282           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5283           remotePointsNew[m].rank  = rrank;
5284         }
5285       } else if ((p >= fMax) && (p < fEnd)) {
5286         /* Old hybrid faces stay the same */
5287         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5288         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5289         remotePointsNew[m].rank  = rrank;
5290         ++m;
5291       } else if ((p >= cStart) && (p < cMax)) {
5292         /* Old interior cells add new cells and interior faces */
5293         for (r = 0; r < 4; ++r, ++m) {
5294           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5295           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5296           remotePointsNew[m].rank  = rrank;
5297         }
5298         for (r = 0; r < 3; ++r, ++m) {
5299           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5300           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5301           remotePointsNew[m].rank  = rrank;
5302         }
5303       } else if ((p >= cStart) && (p < cMax)) {
5304         /* Old hybrid cells add new cells and hybrid face */
5305         for (r = 0; r < 2; ++r, ++m) {
5306           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5307           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5308           remotePointsNew[m].rank  = rrank;
5309         }
5310         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5311         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
5312         remotePointsNew[m].rank  = rrank;
5313         ++m;
5314       }
5315       break;
5316     default:
5317       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5318     }
5319   }
5320   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5321   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5322   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5323   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5324   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5325   PetscFunctionReturn(0);
5326 }
5327 
5328 #undef __FUNCT__
5329 #define __FUNCT__ "CellRefinerCreateLabels"
5330 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5331 {
5332   PetscInt       numLabels, l;
5333   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
5334   PetscErrorCode ierr;
5335 
5336   PetscFunctionBegin;
5337   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5338   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5339   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5340   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5341 
5342   cStartNew = 0;
5343   vStartNew = depthSize[2];
5344   fStartNew = depthSize[2] + depthSize[0];
5345 
5346   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5347   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5348   switch (refiner) {
5349   case 3:
5350     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5351     cMax = PetscMin(cEnd, cMax);
5352     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5353     fMax = PetscMin(fEnd, fMax);
5354   }
5355   for (l = 0; l < numLabels; ++l) {
5356     DMLabel         label, labelNew;
5357     const char     *lname;
5358     PetscBool       isDepth;
5359     IS              valueIS;
5360     const PetscInt *values;
5361     PetscInt        numValues, val;
5362 
5363     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5364     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5365     if (isDepth) continue;
5366     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5367     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5368     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5369     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5370     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5371     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5372     for (val = 0; val < numValues; ++val) {
5373       IS              pointIS;
5374       const PetscInt *points;
5375       PetscInt        numPoints, n;
5376 
5377       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5378       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5379       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5380       for (n = 0; n < numPoints; ++n) {
5381         const PetscInt p = points[n];
5382         switch (refiner) {
5383         case 1:
5384           /* Simplicial 2D */
5385           if ((p >= vStart) && (p < vEnd)) {
5386             /* Old vertices stay the same */
5387             newp = vStartNew + (p - vStart);
5388             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5389           } else if ((p >= fStart) && (p < fEnd)) {
5390             /* Old faces add new faces and vertex */
5391             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5392             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5393             for (r = 0; r < 2; ++r) {
5394               newp = fStartNew + (p - fStart)*2 + r;
5395               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5396             }
5397           } else if ((p >= cStart) && (p < cEnd)) {
5398             /* Old cells add new cells and interior faces */
5399             for (r = 0; r < 4; ++r) {
5400               newp = cStartNew + (p - cStart)*4 + r;
5401               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5402             }
5403             for (r = 0; r < 3; ++r) {
5404               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5405               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5406             }
5407           }
5408           break;
5409         case 2:
5410           /* Hex 2D */
5411           if ((p >= vStart) && (p < vEnd)) {
5412             /* Old vertices stay the same */
5413             newp = vStartNew + (p - vStart);
5414             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5415           } else if ((p >= fStart) && (p < fEnd)) {
5416             /* Old faces add new faces and vertex */
5417             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5418             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5419             for (r = 0; r < 2; ++r) {
5420               newp = fStartNew + (p - fStart)*2 + r;
5421               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5422             }
5423           } else if ((p >= cStart) && (p < cEnd)) {
5424             /* Old cells add new cells and interior faces and vertex */
5425             for (r = 0; r < 4; ++r) {
5426               newp = cStartNew + (p - cStart)*4 + r;
5427               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5428             }
5429             for (r = 0; r < 4; ++r) {
5430               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5431               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5432             }
5433             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5434             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5435           }
5436           break;
5437         case 3:
5438           /* Hybrid simplicial 2D */
5439           if ((p >= vStart) && (p < vEnd)) {
5440             /* Old vertices stay the same */
5441             newp = vStartNew + (p - vStart);
5442             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5443           } else if ((p >= fStart) && (p < fMax)) {
5444             /* Old interior faces add new faces and vertex */
5445             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5446             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5447             for (r = 0; r < 2; ++r) {
5448               newp = fStartNew + (p - fStart)*2 + r;
5449               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5450             }
5451           } else if ((p >= fMax) && (p < fEnd)) {
5452             /* Old hybrid faces stay the same */
5453             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5454             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5455           } else if ((p >= cStart) && (p < cMax)) {
5456             /* Old interior cells add new cells and interior faces */
5457             for (r = 0; r < 4; ++r) {
5458               newp = cStartNew + (p - cStart)*4 + r;
5459               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5460             }
5461             for (r = 0; r < 3; ++r) {
5462               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5463               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5464             }
5465           } else if ((p >= cMax) && (p < cEnd)) {
5466             /* Old hybrid cells add new cells and hybrid face */
5467             for (r = 0; r < 2; ++r) {
5468               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5469               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5470             }
5471             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5472             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5473           }
5474           break;
5475         default:
5476           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5477         }
5478       }
5479       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
5480       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5481     }
5482     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
5483     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
5484     if (0) {
5485       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
5486       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5487       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5488     }
5489   }
5490   PetscFunctionReturn(0);
5491 }
5492 
5493 #undef __FUNCT__
5494 #define __FUNCT__ "DMPlexRefine_Uniform"
5495 /* This will only work for interpolated meshes */
5496 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5497 {
5498   DM             rdm;
5499   PetscInt      *depthSize;
5500   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
5501   PetscErrorCode ierr;
5502 
5503   PetscFunctionBegin;
5504   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
5505   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
5506   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5507   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
5508   /* Calculate number of new points of each depth */
5509   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5510   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
5511   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
5512   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
5513   /* Step 1: Set chart */
5514   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5515   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
5516   /* Step 2: Set cone/support sizes */
5517   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5518   /* Step 3: Setup refined DM */
5519   ierr = DMSetUp(rdm);CHKERRQ(ierr);
5520   /* Step 4: Set cones and supports */
5521   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5522   /* Step 5: Stratify */
5523   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
5524   /* Step 6: Set coordinates for vertices */
5525   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5526   /* Step 7: Create pointSF */
5527   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5528   /* Step 8: Create labels */
5529   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5530   ierr = PetscFree(depthSize);CHKERRQ(ierr);
5531 
5532   *dmRefined = rdm;
5533   PetscFunctionReturn(0);
5534 }
5535 
5536 #undef __FUNCT__
5537 #define __FUNCT__ "DMPlexSetRefinementUniform"
5538 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
5539 {
5540   DM_Plex *mesh = (DM_Plex*) dm->data;
5541 
5542   PetscFunctionBegin;
5543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5544   mesh->refinementUniform = refinementUniform;
5545   PetscFunctionReturn(0);
5546 }
5547 
5548 #undef __FUNCT__
5549 #define __FUNCT__ "DMPlexGetRefinementUniform"
5550 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
5551 {
5552   DM_Plex *mesh = (DM_Plex*) dm->data;
5553 
5554   PetscFunctionBegin;
5555   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5556   PetscValidPointer(refinementUniform,  2);
5557   *refinementUniform = mesh->refinementUniform;
5558   PetscFunctionReturn(0);
5559 }
5560 
5561 #undef __FUNCT__
5562 #define __FUNCT__ "DMPlexSetRefinementLimit"
5563 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
5564 {
5565   DM_Plex *mesh = (DM_Plex*) dm->data;
5566 
5567   PetscFunctionBegin;
5568   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5569   mesh->refinementLimit = refinementLimit;
5570   PetscFunctionReturn(0);
5571 }
5572 
5573 #undef __FUNCT__
5574 #define __FUNCT__ "DMPlexGetRefinementLimit"
5575 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
5576 {
5577   DM_Plex *mesh = (DM_Plex*) dm->data;
5578 
5579   PetscFunctionBegin;
5580   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5581   PetscValidPointer(refinementLimit,  2);
5582   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
5583   *refinementLimit = mesh->refinementLimit;
5584   PetscFunctionReturn(0);
5585 }
5586 
5587 #undef __FUNCT__
5588 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
5589 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
5590 {
5591   PetscInt       dim, cStart, coneSize, cMax;
5592   PetscErrorCode ierr;
5593 
5594   PetscFunctionBegin;
5595   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5596   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
5597   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
5598   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5599   switch (dim) {
5600   case 2:
5601     switch (coneSize) {
5602     case 3:
5603       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
5604       else *cellRefiner = 1; /* Triangular */
5605       break;
5606     case 4:
5607       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
5608       else *cellRefiner = 2; /* Quadrilateral */
5609       break;
5610     default:
5611       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
5612     }
5613     break;
5614   default:
5615     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
5616   }
5617   PetscFunctionReturn(0);
5618 }
5619 
5620 #undef __FUNCT__
5621 #define __FUNCT__ "DMRefine_Plex"
5622 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
5623 {
5624   PetscReal      refinementLimit;
5625   PetscInt       dim, cStart, cEnd;
5626   char           genname[1024], *name = NULL;
5627   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5628   PetscErrorCode ierr;
5629 
5630   PetscFunctionBegin;
5631   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
5632   if (isUniform) {
5633     CellRefiner cellRefiner;
5634 
5635     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
5636     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
5637     PetscFunctionReturn(0);
5638   }
5639   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
5640   if (refinementLimit == 0.0) PetscFunctionReturn(0);
5641   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5642   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5643   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5644   if (flg) name = genname;
5645   if (name) {
5646     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5647     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5648     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5649   }
5650   switch (dim) {
5651   case 2:
5652     if (!name || isTriangle) {
5653 #if defined(PETSC_HAVE_TRIANGLE)
5654       double  *maxVolumes;
5655       PetscInt c;
5656 
5657       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5658       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5659       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5660 #else
5661       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
5662 #endif
5663     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5664     break;
5665   case 3:
5666     if (!name || isCTetgen) {
5667 #if defined(PETSC_HAVE_CTETGEN)
5668       PetscReal *maxVolumes;
5669       PetscInt   c;
5670 
5671       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
5672       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5673       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5674 #else
5675       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5676 #endif
5677     } else if (isTetgen) {
5678 #if defined(PETSC_HAVE_TETGEN)
5679       double  *maxVolumes;
5680       PetscInt c;
5681 
5682       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5683       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5684       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5685 #else
5686       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5687 #endif
5688     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5689     break;
5690   default:
5691     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
5692   }
5693   PetscFunctionReturn(0);
5694 }
5695 
5696 #undef __FUNCT__
5697 #define __FUNCT__ "DMPlexGetDepth"
5698 /*@
5699   DMPlexGetDepth - get the number of strata
5700 
5701   Not Collective
5702 
5703   Input Parameters:
5704 . dm           - The DMPlex object
5705 
5706   Output Parameters:
5707 . depth - number of strata
5708 
5709   Level: developer
5710 
5711   Notes:
5712   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
5713 
5714 .keywords: mesh, points
5715 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
5716 @*/
5717 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5718 {
5719   PetscInt       d;
5720   PetscErrorCode ierr;
5721 
5722   PetscFunctionBegin;
5723   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5724   PetscValidPointer(depth, 2);
5725   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
5726   *depth = d-1;
5727   PetscFunctionReturn(0);
5728 }
5729 
5730 #undef __FUNCT__
5731 #define __FUNCT__ "DMPlexGetDepthStratum"
5732 /*@
5733   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
5734 
5735   Not Collective
5736 
5737   Input Parameters:
5738 + dm           - The DMPlex object
5739 - stratumValue - The requested depth
5740 
5741   Output Parameters:
5742 + start - The first point at this depth
5743 - end   - One beyond the last point at this depth
5744 
5745   Level: developer
5746 
5747 .keywords: mesh, points
5748 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
5749 @*/
5750 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5751 {
5752   DM_Plex       *mesh = (DM_Plex*) dm->data;
5753   DMLabel        next  = mesh->labels;
5754   PetscBool      flg   = PETSC_FALSE;
5755   PetscInt       depth;
5756   PetscErrorCode ierr;
5757 
5758   PetscFunctionBegin;
5759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5760   if (stratumValue < 0) {
5761     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
5762     PetscFunctionReturn(0);
5763   } else {
5764     PetscInt pStart, pEnd;
5765 
5766     if (start) *start = 0;
5767     if (end)   *end   = 0;
5768     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5769     if (pStart == pEnd) PetscFunctionReturn(0);
5770   }
5771   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
5772   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
5773   /* We should have a generic GetLabel() and a Label class */
5774   while (next) {
5775     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
5776     if (flg) break;
5777     next = next->next;
5778   }
5779   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
5780   depth = stratumValue;
5781   if ((depth < 0) || (depth >= next->numStrata)) {
5782     if (start) *start = 0;
5783     if (end)   *end   = 0;
5784   } else {
5785     if (start) *start = next->points[next->stratumOffsets[depth]];
5786     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
5787   }
5788   PetscFunctionReturn(0);
5789 }
5790 
5791 #undef __FUNCT__
5792 #define __FUNCT__ "DMPlexGetHeightStratum"
5793 /*@
5794   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
5795 
5796   Not Collective
5797 
5798   Input Parameters:
5799 + dm           - The DMPlex object
5800 - stratumValue - The requested height
5801 
5802   Output Parameters:
5803 + start - The first point at this height
5804 - end   - One beyond the last point at this height
5805 
5806   Level: developer
5807 
5808 .keywords: mesh, points
5809 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
5810 @*/
5811 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5812 {
5813   DM_Plex       *mesh = (DM_Plex*) dm->data;
5814   DMLabel        next  = mesh->labels;
5815   PetscBool      flg   = PETSC_FALSE;
5816   PetscInt       depth;
5817   PetscErrorCode ierr;
5818 
5819   PetscFunctionBegin;
5820   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5821   if (stratumValue < 0) {
5822     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
5823   } else {
5824     PetscInt pStart, pEnd;
5825 
5826     if (start) *start = 0;
5827     if (end)   *end   = 0;
5828     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5829     if (pStart == pEnd) PetscFunctionReturn(0);
5830   }
5831   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
5832   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
5833   /* We should have a generic GetLabel() and a Label class */
5834   while (next) {
5835     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
5836     if (flg) break;
5837     next = next->next;
5838   }
5839   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
5840   depth = next->stratumValues[next->numStrata-1] - stratumValue;
5841   if ((depth < 0) || (depth >= next->numStrata)) {
5842     if (start) *start = 0;
5843     if (end)   *end   = 0;
5844   } else {
5845     if (start) *start = next->points[next->stratumOffsets[depth]];
5846     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
5847   }
5848   PetscFunctionReturn(0);
5849 }
5850 
5851 #undef __FUNCT__
5852 #define __FUNCT__ "DMPlexCreateSectionInitial"
5853 /* Set the number of dof on each point and separate by fields */
5854 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
5855 {
5856   PetscInt      *numDofTot;
5857   PetscInt       pStart = 0, pEnd = 0;
5858   PetscInt       p, d, f;
5859   PetscErrorCode ierr;
5860 
5861   PetscFunctionBegin;
5862   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
5863   for (d = 0; d <= dim; ++d) {
5864     numDofTot[d] = 0;
5865     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
5866   }
5867   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
5868   if (numFields > 0) {
5869     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
5870     if (numComp) {
5871       for (f = 0; f < numFields; ++f) {
5872         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
5873       }
5874     }
5875   }
5876   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5877   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
5878   for (d = 0; d <= dim; ++d) {
5879     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
5880     for (p = pStart; p < pEnd; ++p) {
5881       for (f = 0; f < numFields; ++f) {
5882         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
5883       }
5884       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
5885     }
5886   }
5887   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
5888   PetscFunctionReturn(0);
5889 }
5890 
5891 #undef __FUNCT__
5892 #define __FUNCT__ "DMPlexCreateSectionBCDof"
5893 /* Set the number of dof on each point and separate by fields
5894    If constDof is PETSC_DETERMINE, constrain every dof on the point
5895 */
5896 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
5897 {
5898   PetscInt       numFields;
5899   PetscInt       bc;
5900   PetscErrorCode ierr;
5901 
5902   PetscFunctionBegin;
5903   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5904   for (bc = 0; bc < numBC; ++bc) {
5905     PetscInt        field = 0;
5906     const PetscInt *idx;
5907     PetscInt        n, i;
5908 
5909     if (numFields) field = bcField[bc];
5910     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
5911     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
5912     for (i = 0; i < n; ++i) {
5913       const PetscInt p        = idx[i];
5914       PetscInt       numConst = constDof;
5915 
5916       /* Constrain every dof on the point */
5917       if (numConst < 0) {
5918         if (numFields) {
5919           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
5920         } else {
5921           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
5922         }
5923       }
5924       if (numFields) {
5925         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
5926       }
5927       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
5928     }
5929     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
5930   }
5931   PetscFunctionReturn(0);
5932 }
5933 
5934 #undef __FUNCT__
5935 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
5936 /* Set the constrained indices on each point and separate by fields */
5937 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
5938 {
5939   PetscInt      *maxConstraints;
5940   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
5941   PetscErrorCode ierr;
5942 
5943   PetscFunctionBegin;
5944   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5945   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5946   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
5947   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
5948   for (p = pStart; p < pEnd; ++p) {
5949     PetscInt cdof;
5950 
5951     if (numFields) {
5952       for (f = 0; f < numFields; ++f) {
5953         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
5954         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
5955       }
5956     } else {
5957       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
5958       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
5959     }
5960   }
5961   for (f = 0; f < numFields; ++f) {
5962     maxConstraints[numFields] += maxConstraints[f];
5963   }
5964   if (maxConstraints[numFields]) {
5965     PetscInt *indices;
5966 
5967     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
5968     for (p = pStart; p < pEnd; ++p) {
5969       PetscInt cdof, d;
5970 
5971       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
5972       if (cdof) {
5973         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
5974         if (numFields) {
5975           PetscInt numConst = 0, foff = 0;
5976 
5977           for (f = 0; f < numFields; ++f) {
5978             PetscInt cfdof, fdof;
5979 
5980             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
5981             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
5982             /* Change constraint numbering from absolute local dof number to field relative local dof number */
5983             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
5984             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
5985             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
5986             numConst += cfdof;
5987             foff     += fdof;
5988           }
5989           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
5990         } else {
5991           for (d = 0; d < cdof; ++d) indices[d] = d;
5992         }
5993         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
5994       }
5995     }
5996     ierr = PetscFree(indices);CHKERRQ(ierr);
5997   }
5998   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
5999   PetscFunctionReturn(0);
6000 }
6001 
6002 #undef __FUNCT__
6003 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
6004 /* Set the constrained field indices on each point */
6005 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6006 {
6007   const PetscInt *points, *indices;
6008   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6009   PetscErrorCode  ierr;
6010 
6011   PetscFunctionBegin;
6012   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6013   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
6014 
6015   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
6016   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
6017   if (!constraintIndices) {
6018     PetscInt *idx, i;
6019 
6020     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6021     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
6022     for (i = 0; i < maxDof; ++i) idx[i] = i;
6023     for (p = 0; p < numPoints; ++p) {
6024       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
6025     }
6026     ierr = PetscFree(idx);CHKERRQ(ierr);
6027   } else {
6028     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
6029     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
6030     for (p = 0; p < numPoints; ++p) {
6031       PetscInt fcdof;
6032 
6033       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
6034       if (fcdof != numConstraints) SETERRQ4(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
6035       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
6036     }
6037     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
6038   }
6039   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
6040   PetscFunctionReturn(0);
6041 }
6042 
6043 #undef __FUNCT__
6044 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
6045 /* Set the constrained indices on each point and separate by fields */
6046 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6047 {
6048   PetscInt      *indices;
6049   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
6050   PetscErrorCode ierr;
6051 
6052   PetscFunctionBegin;
6053   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6054   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6055   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6056   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6057   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6058   for (p = pStart; p < pEnd; ++p) {
6059     PetscInt cdof, d;
6060 
6061     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6062     if (cdof) {
6063       PetscInt numConst = 0, foff = 0;
6064 
6065       for (f = 0; f < numFields; ++f) {
6066         const PetscInt *fcind;
6067         PetscInt        fdof, fcdof;
6068 
6069         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6070         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
6071         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
6072         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6073         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6074         foff     += fdof;
6075         numConst += fcdof;
6076       }
6077       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6078       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6079     }
6080   }
6081   ierr = PetscFree(indices);CHKERRQ(ierr);
6082   PetscFunctionReturn(0);
6083 }
6084 
6085 #undef __FUNCT__
6086 #define __FUNCT__ "DMPlexCreateSection"
6087 /*@C
6088   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
6089 
6090   Not Collective
6091 
6092   Input Parameters:
6093 + dm        - The DMPlex object
6094 . dim       - The spatial dimension of the problem
6095 . numFields - The number of fields in the problem
6096 . numComp   - An array of size numFields that holds the number of components for each field
6097 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6098 . numBC     - The number of boundary conditions
6099 . bcField   - An array of size numBC giving the field number for each boundry condition
6100 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
6101 
6102   Output Parameter:
6103 . section - The PetscSection object
6104 
6105   Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the
6106   nubmer of dof for field 0 on each edge.
6107 
6108   Level: developer
6109 
6110   Fortran Notes:
6111   A Fortran 90 version is available as DMPlexCreateSectionF90()
6112 
6113 .keywords: mesh, elements
6114 .seealso: DMPlexCreate(), PetscSectionCreate()
6115 @*/
6116 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6117 {
6118   PetscErrorCode ierr;
6119 
6120   PetscFunctionBegin;
6121   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
6122   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
6123   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
6124   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
6125   {
6126     PetscBool view = PETSC_FALSE;
6127 
6128     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
6129     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
6130   }
6131   PetscFunctionReturn(0);
6132 }
6133 
6134 #undef __FUNCT__
6135 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
6136 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6137 {
6138   PetscSection   section;
6139   PetscErrorCode ierr;
6140 
6141   PetscFunctionBegin;
6142   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
6143   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6144   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
6145   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6146   PetscFunctionReturn(0);
6147 }
6148 
6149 #undef __FUNCT__
6150 #define __FUNCT__ "DMPlexGetCoordinateSection"
6151 /*@
6152   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6153 
6154   Not Collective
6155 
6156   Input Parameter:
6157 . dm - The DMPlex object
6158 
6159   Output Parameter:
6160 . section - The PetscSection object
6161 
6162   Level: intermediate
6163 
6164 .keywords: mesh, coordinates
6165 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6166 @*/
6167 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6168 {
6169   DM             cdm;
6170   PetscErrorCode ierr;
6171 
6172   PetscFunctionBegin;
6173   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6174   PetscValidPointer(section, 2);
6175   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6176   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
6177   PetscFunctionReturn(0);
6178 }
6179 
6180 #undef __FUNCT__
6181 #define __FUNCT__ "DMPlexSetCoordinateSection"
6182 /*@
6183   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
6184 
6185   Not Collective
6186 
6187   Input Parameters:
6188 + dm      - The DMPlex object
6189 - section - The PetscSection object
6190 
6191   Level: intermediate
6192 
6193 .keywords: mesh, coordinates
6194 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6195 @*/
6196 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6197 {
6198   DM             cdm;
6199   PetscErrorCode ierr;
6200 
6201   PetscFunctionBegin;
6202   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6203   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
6204   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6205   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
6206   PetscFunctionReturn(0);
6207 }
6208 
6209 #undef __FUNCT__
6210 #define __FUNCT__ "DMPlexGetConeSection"
6211 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6212 {
6213   DM_Plex *mesh = (DM_Plex*) dm->data;
6214 
6215   PetscFunctionBegin;
6216   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6217   if (section) *section = mesh->coneSection;
6218   PetscFunctionReturn(0);
6219 }
6220 
6221 #undef __FUNCT__
6222 #define __FUNCT__ "DMPlexGetCones"
6223 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6224 {
6225   DM_Plex *mesh = (DM_Plex*) dm->data;
6226 
6227   PetscFunctionBegin;
6228   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6229   if (cones) *cones = mesh->cones;
6230   PetscFunctionReturn(0);
6231 }
6232 
6233 #undef __FUNCT__
6234 #define __FUNCT__ "DMPlexGetConeOrientations"
6235 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6236 {
6237   DM_Plex *mesh = (DM_Plex*) dm->data;
6238 
6239   PetscFunctionBegin;
6240   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6241   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6242   PetscFunctionReturn(0);
6243 }
6244 
6245 /******************************** FEM Support **********************************/
6246 
6247 #undef __FUNCT__
6248 #define __FUNCT__ "DMPlexVecGetClosure"
6249 /*@C
6250   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6251 
6252   Not collective
6253 
6254   Input Parameters:
6255 + dm - The DM
6256 . section - The section describing the layout in v, or NULL to use the default section
6257 . v - The local vector
6258 - point - The sieve point in the DM
6259 
6260   Output Parameters:
6261 + csize - The number of values in the closure, or NULL
6262 - values - The array of values, which is a borrowed array and should not be freed
6263 
6264   Fortran Notes:
6265   Since it returns an array, this routine is only available in Fortran 90, and you must
6266   include petsc.h90 in your code.
6267 
6268   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6269 
6270   Level: intermediate
6271 
6272 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6273 @*/
6274 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6275 {
6276   PetscScalar   *array, *vArray;
6277   PetscInt      *points = NULL;
6278   PetscInt       offsets[32];
6279   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
6280   PetscErrorCode ierr;
6281 
6282   PetscFunctionBegin;
6283   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6284   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6285   if (!section) {
6286     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6287   }
6288   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6289   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6290   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6291   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6292   /* Compress out points not in the section */
6293   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6294   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6295     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6296       points[q*2]   = points[p];
6297       points[q*2+1] = points[p+1];
6298       ++q;
6299     }
6300   }
6301   numPoints = q;
6302   for (p = 0, size = 0; p < numPoints*2; p += 2) {
6303     PetscInt dof, fdof;
6304 
6305     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6306     for (f = 0; f < numFields; ++f) {
6307       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6308       offsets[f+1] += fdof;
6309     }
6310     size += dof;
6311   }
6312   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6313   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
6314   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6315   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6316   for (p = 0; p < numPoints*2; p += 2) {
6317     PetscInt     o = points[p+1];
6318     PetscInt     dof, off, d;
6319     PetscScalar *varr;
6320 
6321     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6322     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
6323     varr = &vArray[off];
6324     if (numFields) {
6325       PetscInt fdof, foff, fcomp, f, c;
6326 
6327       for (f = 0, foff = 0; f < numFields; ++f) {
6328         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6329         if (o >= 0) {
6330           for (d = 0; d < fdof; ++d, ++offsets[f]) {
6331             array[offsets[f]] = varr[foff+d];
6332           }
6333         } else {
6334           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6335           for (d = fdof/fcomp-1; d >= 0; --d) {
6336             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
6337               array[offsets[f]] = varr[foff+d*fcomp+c];
6338             }
6339           }
6340         }
6341         foff += fdof;
6342       }
6343     } else {
6344       if (o >= 0) {
6345         for (d = 0; d < dof; ++d, ++offsets[0]) {
6346           array[offsets[0]] = varr[d];
6347         }
6348       } else {
6349         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6350           array[offsets[0]] = varr[d];
6351         }
6352       }
6353     }
6354   }
6355   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6356   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
6357   if (csize) *csize = size;
6358   *values = array;
6359   PetscFunctionReturn(0);
6360 }
6361 
6362 #undef __FUNCT__
6363 #define __FUNCT__ "DMPlexVecRestoreClosure"
6364 /*@C
6365   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6366 
6367   Not collective
6368 
6369   Input Parameters:
6370 + dm - The DM
6371 . section - The section describing the layout in v, or NULL to use the default section
6372 . v - The local vector
6373 . point - The sieve point in the DM
6374 . csize - The number of values in the closure, or NULL
6375 - values - The array of values, which is a borrowed array and should not be freed
6376 
6377   Fortran Notes:
6378   Since it returns an array, this routine is only available in Fortran 90, and you must
6379   include petsc.h90 in your code.
6380 
6381   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6382 
6383   Level: intermediate
6384 
6385 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6386 @*/
6387 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6388 {
6389   PetscInt       size = 0;
6390   PetscErrorCode ierr;
6391 
6392   PetscFunctionBegin;
6393   /* Should work without recalculating size */
6394   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
6395   PetscFunctionReturn(0);
6396 }
6397 
6398 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
6399 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
6400 
6401 #undef __FUNCT__
6402 #define __FUNCT__ "updatePoint_private"
6403 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6404 {
6405   PetscInt        cdof;   /* The number of constraints on this point */
6406   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6407   PetscScalar    *a;
6408   PetscInt        off, cind = 0, k;
6409   PetscErrorCode  ierr;
6410 
6411   PetscFunctionBegin;
6412   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6413   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6414   a    = &array[off];
6415   if (!cdof || setBC) {
6416     if (orientation >= 0) {
6417       for (k = 0; k < dof; ++k) {
6418         fuse(&a[k], values[k]);
6419       }
6420     } else {
6421       for (k = 0; k < dof; ++k) {
6422         fuse(&a[k], values[dof-k-1]);
6423       }
6424     }
6425   } else {
6426     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6427     if (orientation >= 0) {
6428       for (k = 0; k < dof; ++k) {
6429         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6430         fuse(&a[k], values[k]);
6431       }
6432     } else {
6433       for (k = 0; k < dof; ++k) {
6434         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6435         fuse(&a[k], values[dof-k-1]);
6436       }
6437     }
6438   }
6439   PetscFunctionReturn(0);
6440 }
6441 
6442 #undef __FUNCT__
6443 #define __FUNCT__ "updatePointFields_private"
6444 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6445 {
6446   PetscScalar   *a;
6447   PetscInt       numFields, off, foff, f;
6448   PetscErrorCode ierr;
6449 
6450   PetscFunctionBegin;
6451   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6452   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6453   a    = &array[off];
6454   for (f = 0, foff = 0; f < numFields; ++f) {
6455     PetscInt        fdof, fcomp, fcdof;
6456     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6457     PetscInt        cind = 0, k, c;
6458 
6459     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6460     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6461     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6462     if (!fcdof || setBC) {
6463       if (orientation >= 0) {
6464         for (k = 0; k < fdof; ++k) {
6465           fuse(&a[foff+k], values[foffs[f]+k]);
6466         }
6467       } else {
6468         for (k = fdof/fcomp-1; k >= 0; --k) {
6469           for (c = 0; c < fcomp; ++c) {
6470             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6471           }
6472         }
6473       }
6474     } else {
6475       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6476       if (orientation >= 0) {
6477         for (k = 0; k < fdof; ++k) {
6478           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
6479           fuse(&a[foff+k], values[foffs[f]+k]);
6480         }
6481       } else {
6482         for (k = fdof/fcomp-1; k >= 0; --k) {
6483           for (c = 0; c < fcomp; ++c) {
6484             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
6485             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6486           }
6487         }
6488       }
6489     }
6490     foff     += fdof;
6491     foffs[f] += fdof;
6492   }
6493   PetscFunctionReturn(0);
6494 }
6495 
6496 #undef __FUNCT__
6497 #define __FUNCT__ "DMPlexVecSetClosure"
6498 /*@C
6499   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6500 
6501   Not collective
6502 
6503   Input Parameters:
6504 + dm - The DM
6505 . section - The section describing the layout in v, or NULL to use the default sectionw
6506 . v - The local vector
6507 . point - The sieve point in the DM
6508 . values - The array of values, which is a borrowed array and should not be freed
6509 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6510 
6511   Fortran Notes:
6512   Since it returns an array, this routine is only available in Fortran 90, and you must
6513   include petsc.h90 in your code.
6514 
6515   Level: intermediate
6516 
6517 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6518 @*/
6519 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6520 {
6521   PetscScalar   *array;
6522   PetscInt      *points = NULL;
6523   PetscInt       offsets[32];
6524   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
6525   PetscErrorCode ierr;
6526 
6527   PetscFunctionBegin;
6528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6529   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6530   if (!section) {
6531     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6532   }
6533   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6534   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6535   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6536   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6537   /* Compress out points not in the section */
6538   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6539   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6540     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6541       points[q*2]   = points[p];
6542       points[q*2+1] = points[p+1];
6543       ++q;
6544     }
6545   }
6546   numPoints = q;
6547   for (p = 0; p < numPoints*2; p += 2) {
6548     PetscInt fdof;
6549 
6550     for (f = 0; f < numFields; ++f) {
6551       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6552       offsets[f+1] += fdof;
6553     }
6554   }
6555   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6556   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6557   if (numFields) {
6558     switch (mode) {
6559     case INSERT_VALUES:
6560       for (p = 0; p < numPoints*2; p += 2) {
6561         PetscInt o = points[p+1];
6562         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
6563       } break;
6564     case INSERT_ALL_VALUES:
6565       for (p = 0; p < numPoints*2; p += 2) {
6566         PetscInt o = points[p+1];
6567         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
6568       } break;
6569     case ADD_VALUES:
6570       for (p = 0; p < numPoints*2; p += 2) {
6571         PetscInt o = points[p+1];
6572         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
6573       } break;
6574     case ADD_ALL_VALUES:
6575       for (p = 0; p < numPoints*2; p += 2) {
6576         PetscInt o = points[p+1];
6577         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
6578       } break;
6579     default:
6580       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6581     }
6582   } else {
6583     switch (mode) {
6584     case INSERT_VALUES:
6585       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6586         PetscInt o = points[p+1];
6587         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6588         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
6589       } break;
6590     case INSERT_ALL_VALUES:
6591       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6592         PetscInt o = points[p+1];
6593         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6594         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
6595       } break;
6596     case ADD_VALUES:
6597       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6598         PetscInt o = points[p+1];
6599         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6600         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
6601       } break;
6602     case ADD_ALL_VALUES:
6603       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6604         PetscInt o = points[p+1];
6605         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6606         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
6607       } break;
6608     default:
6609       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6610     }
6611   }
6612   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6613   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6614   PetscFunctionReturn(0);
6615 }
6616 
6617 #undef __FUNCT__
6618 #define __FUNCT__ "DMPlexPrintMatSetValues"
6619 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
6620 {
6621   PetscMPIInt    rank;
6622   PetscInt       i, j;
6623   PetscErrorCode ierr;
6624 
6625   PetscFunctionBegin;
6626   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
6627   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
6628   for (i = 0; i < numIndices; i++) {
6629     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
6630   }
6631   for (i = 0; i < numIndices; i++) {
6632     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
6633     for (j = 0; j < numIndices; j++) {
6634 #if defined(PETSC_USE_COMPLEX)
6635       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
6636 #else
6637       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
6638 #endif
6639     }
6640     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6641   }
6642   PetscFunctionReturn(0);
6643 }
6644 
6645 #undef __FUNCT__
6646 #define __FUNCT__ "indicesPoint_private"
6647 /* . off - The global offset of this point */
6648 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
6649 {
6650   PetscInt        dof;    /* The number of unknowns on this point */
6651   PetscInt        cdof;   /* The number of constraints on this point */
6652   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6653   PetscInt        cind = 0, k;
6654   PetscErrorCode  ierr;
6655 
6656   PetscFunctionBegin;
6657   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6658   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6659   if (!cdof || setBC) {
6660     if (orientation >= 0) {
6661       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
6662     } else {
6663       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
6664     }
6665   } else {
6666     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6667     if (orientation >= 0) {
6668       for (k = 0; k < dof; ++k) {
6669         if ((cind < cdof) && (k == cdofs[cind])) {
6670           /* Insert check for returning constrained indices */
6671           indices[*loff+k] = -(off+k+1);
6672           ++cind;
6673         } else {
6674           indices[*loff+k] = off+k-cind;
6675         }
6676       }
6677     } else {
6678       for (k = 0; k < dof; ++k) {
6679         if ((cind < cdof) && (k == cdofs[cind])) {
6680           /* Insert check for returning constrained indices */
6681           indices[*loff+dof-k-1] = -(off+k+1);
6682           ++cind;
6683         } else {
6684           indices[*loff+dof-k-1] = off+k-cind;
6685         }
6686       }
6687     }
6688   }
6689   *loff += dof;
6690   PetscFunctionReturn(0);
6691 }
6692 
6693 #undef __FUNCT__
6694 #define __FUNCT__ "indicesPointFields_private"
6695 /* . off - The global offset of this point */
6696 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
6697 {
6698   PetscInt       numFields, foff, f;
6699   PetscErrorCode ierr;
6700 
6701   PetscFunctionBegin;
6702   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6703   for (f = 0, foff = 0; f < numFields; ++f) {
6704     PetscInt        fdof, fcomp, cfdof;
6705     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6706     PetscInt        cind = 0, k, c;
6707 
6708     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6709     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6710     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6711     if (!cfdof || setBC) {
6712       if (orientation >= 0) {
6713         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
6714       } else {
6715         for (k = fdof/fcomp-1; k >= 0; --k) {
6716           for (c = 0; c < fcomp; ++c) {
6717             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
6718           }
6719         }
6720       }
6721     } else {
6722       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6723       if (orientation >= 0) {
6724         for (k = 0; k < fdof; ++k) {
6725           if ((cind < cfdof) && (k == fcdofs[cind])) {
6726             indices[foffs[f]+k] = -(off+foff+k+1);
6727             ++cind;
6728           } else {
6729             indices[foffs[f]+k] = off+foff+k-cind;
6730           }
6731         }
6732       } else {
6733         for (k = fdof/fcomp-1; k >= 0; --k) {
6734           for (c = 0; c < fcomp; ++c) {
6735             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
6736               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
6737               ++cind;
6738             } else {
6739               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
6740             }
6741           }
6742         }
6743       }
6744     }
6745     foff     += fdof - cfdof;
6746     foffs[f] += fdof;
6747   }
6748   PetscFunctionReturn(0);
6749 }
6750 
6751 #undef __FUNCT__
6752 #define __FUNCT__ "DMPlexMatSetClosure"
6753 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6754 {
6755   DM_Plex       *mesh   = (DM_Plex*) dm->data;
6756   PetscInt      *points = NULL;
6757   PetscInt      *indices;
6758   PetscInt       offsets[32];
6759   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
6760   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
6761   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
6762   PetscErrorCode ierr;
6763 
6764   PetscFunctionBegin;
6765   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6766   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
6767   if (useDefault) {
6768     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6769   }
6770   if (useGlobalDefault) {
6771     if (useDefault) {
6772       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
6773     } else {
6774       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6775     }
6776   }
6777   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6778   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6779   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6780   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6781   /* Compress out points not in the section */
6782   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6783   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6784     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6785       points[q*2]   = points[p];
6786       points[q*2+1] = points[p+1];
6787       ++q;
6788     }
6789   }
6790   numPoints = q;
6791   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
6792     PetscInt fdof;
6793 
6794     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6795     for (f = 0; f < numFields; ++f) {
6796       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6797       offsets[f+1] += fdof;
6798     }
6799     numIndices += dof;
6800   }
6801   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6802 
6803   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
6804   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
6805   if (numFields) {
6806     for (p = 0; p < numPoints*2; p += 2) {
6807       PetscInt o = points[p+1];
6808       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
6809       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
6810     }
6811   } else {
6812     for (p = 0, off = 0; p < numPoints*2; p += 2) {
6813       PetscInt o = points[p+1];
6814       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
6815       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
6816     }
6817   }
6818   if (useGlobalDefault && !useDefault) {
6819     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6820   }
6821   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
6822   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6823   if (ierr) {
6824     PetscMPIInt    rank;
6825     PetscErrorCode ierr2;
6826 
6827     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6828     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6829     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
6830     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
6831     CHKERRQ(ierr);
6832   }
6833   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6834   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
6835   PetscFunctionReturn(0);
6836 }
6837 
6838 #undef __FUNCT__
6839 #define __FUNCT__ "DMPlexGetHybridBounds"
6840 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6841 {
6842   DM_Plex       *mesh = (DM_Plex*) dm->data;
6843   PetscInt       dim;
6844   PetscErrorCode ierr;
6845 
6846   PetscFunctionBegin;
6847   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6848   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6849   if (cMax) *cMax = mesh->hybridPointMax[dim];
6850   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
6851   if (eMax) *eMax = mesh->hybridPointMax[1];
6852   if (vMax) *vMax = mesh->hybridPointMax[0];
6853   PetscFunctionReturn(0);
6854 }
6855 
6856 #undef __FUNCT__
6857 #define __FUNCT__ "DMPlexSetHybridBounds"
6858 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6859 {
6860   DM_Plex       *mesh = (DM_Plex*) dm->data;
6861   PetscInt       dim;
6862   PetscErrorCode ierr;
6863 
6864   PetscFunctionBegin;
6865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6866   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6867   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
6868   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
6869   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
6870   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
6871   PetscFunctionReturn(0);
6872 }
6873 
6874 #undef __FUNCT__
6875 #define __FUNCT__ "DMPlexGetVTKCellHeight"
6876 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6877 {
6878   DM_Plex *mesh = (DM_Plex*) dm->data;
6879 
6880   PetscFunctionBegin;
6881   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6882   PetscValidPointer(cellHeight, 2);
6883   *cellHeight = mesh->vtkCellHeight;
6884   PetscFunctionReturn(0);
6885 }
6886 
6887 #undef __FUNCT__
6888 #define __FUNCT__ "DMPlexSetVTKCellHeight"
6889 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6890 {
6891   DM_Plex *mesh = (DM_Plex*) dm->data;
6892 
6893   PetscFunctionBegin;
6894   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6895   mesh->vtkCellHeight = cellHeight;
6896   PetscFunctionReturn(0);
6897 }
6898 
6899 #undef __FUNCT__
6900 #define __FUNCT__ "DMPlexCreateNumbering_Private"
6901 /* We can easily have a form that takes an IS instead */
6902 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
6903 {
6904   PetscSection   section, globalSection;
6905   PetscInt      *numbers, p;
6906   PetscErrorCode ierr;
6907 
6908   PetscFunctionBegin;
6909   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6910   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
6911   for (p = pStart; p < pEnd; ++p) {
6912     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
6913   }
6914   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
6915   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6916   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
6917   for (p = pStart; p < pEnd; ++p) {
6918     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
6919   }
6920   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
6921   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6922   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6923   PetscFunctionReturn(0);
6924 }
6925 
6926 #undef __FUNCT__
6927 #define __FUNCT__ "DMPlexGetCellNumbering"
6928 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6929 {
6930   DM_Plex       *mesh = (DM_Plex*) dm->data;
6931   PetscInt       cellHeight, cStart, cEnd, cMax;
6932   PetscErrorCode ierr;
6933 
6934   PetscFunctionBegin;
6935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6936   if (!mesh->globalCellNumbers) {
6937     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
6938     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6939     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6940     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
6941     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
6942   }
6943   *globalCellNumbers = mesh->globalCellNumbers;
6944   PetscFunctionReturn(0);
6945 }
6946 
6947 #undef __FUNCT__
6948 #define __FUNCT__ "DMPlexGetVertexNumbering"
6949 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6950 {
6951   DM_Plex       *mesh = (DM_Plex*) dm->data;
6952   PetscInt       vStart, vEnd, vMax;
6953   PetscErrorCode ierr;
6954 
6955   PetscFunctionBegin;
6956   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6957   if (!mesh->globalVertexNumbers) {
6958     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6959     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
6960     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
6961     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
6962   }
6963   *globalVertexNumbers = mesh->globalVertexNumbers;
6964   PetscFunctionReturn(0);
6965 }
6966 
6967 
6968 #undef __FUNCT__
6969 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
6970 /*@C
6971   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
6972   the local section and an SF describing the section point overlap.
6973 
6974   Input Parameters:
6975   + s - The PetscSection for the local field layout
6976   . sf - The SF describing parallel layout of the section points
6977   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
6978   . label - The label specifying the points
6979   - labelValue - The label stratum specifying the points
6980 
6981   Output Parameter:
6982   . gsection - The PetscSection for the global field layout
6983 
6984   Note: This gives negative sizes and offsets to points not owned by this process
6985 
6986   Level: developer
6987 
6988 .seealso: PetscSectionCreate()
6989 @*/
6990 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
6991 {
6992   PetscInt      *neg;
6993   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
6994   PetscErrorCode ierr;
6995 
6996   PetscFunctionBegin;
6997   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
6998   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
6999   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
7000   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
7001   /* Mark ghost points with negative dof */
7002   for (p = pStart; p < pEnd; ++p) {
7003     PetscInt value;
7004 
7005     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
7006     if (value != labelValue) continue;
7007     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
7008     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
7009     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
7010     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
7011     neg[p-pStart] = -(dof+1);
7012   }
7013   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
7014   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
7015   if (nroots >= 0) {
7016     if (nroots > pEnd - pStart) {
7017       PetscInt *tmpDof;
7018       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7019       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
7020       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7021       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7022       for (p = pStart; p < pEnd; ++p) {
7023         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
7024       }
7025       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
7026     } else {
7027       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7028       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7029     }
7030   }
7031   /* Calculate new sizes, get proccess offset, and calculate point offsets */
7032   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7033     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
7034 
7035     (*gsection)->atlasOff[p] = off;
7036 
7037     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
7038   }
7039   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
7040   globalOff -= off;
7041   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7042     (*gsection)->atlasOff[p] += globalOff;
7043 
7044     neg[p] = -((*gsection)->atlasOff[p]+1);
7045   }
7046   /* Put in negative offsets for ghost points */
7047   if (nroots >= 0) {
7048     if (nroots > pEnd - pStart) {
7049       PetscInt *tmpOff;
7050       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7051       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
7052       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7053       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7054       for (p = pStart; p < pEnd; ++p) {
7055         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
7056       }
7057       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
7058     } else {
7059       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7060       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7061     }
7062   }
7063   ierr = PetscFree(neg);CHKERRQ(ierr);
7064   PetscFunctionReturn(0);
7065 }
7066