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