xref: /petsc/src/dm/impls/plex/plex.c (revision 2e1b13c25062c3c40593ce7412c5cd227259ade7)
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, *partPoints = NULL;
2496   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2497   PetscErrorCode  ierr;
2498 
2499   PetscFunctionBegin;
2500   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2501   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2502   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2503   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2504   for (rank = rStart; rank < rEnd; ++rank) {
2505     PetscInt partSize = 0;
2506     PetscInt numPoints, offset, p;
2507 
2508     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2509     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2510     for (p = 0; p < numPoints; ++p) {
2511       PetscInt  point   = partArray[offset+p], closureSize, c;
2512       PetscInt *closure = NULL;
2513 
2514       /* TODO Include support for height > 0 case */
2515       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2516       /* Merge into existing points */
2517       if (partSize+closureSize > maxPartSize) {
2518         PetscInt *tmpPoints;
2519 
2520         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2521         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2522         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2523         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2524 
2525         partPoints = tmpPoints;
2526       }
2527       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2528       partSize += closureSize;
2529 
2530       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2531       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2532     }
2533     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
2534   }
2535   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
2536   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
2537   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
2538 
2539   for (rank = rStart; rank < rEnd; ++rank) {
2540     PetscInt partSize = 0, newOffset;
2541     PetscInt numPoints, offset, p;
2542 
2543     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2544     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2545     for (p = 0; p < numPoints; ++p) {
2546       PetscInt  point   = partArray[offset+p], closureSize, c;
2547       PetscInt *closure = NULL;
2548 
2549       /* TODO Include support for height > 0 case */
2550       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2551       /* Merge into existing points */
2552       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
2553       partSize += closureSize;
2554 
2555       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
2556       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2557     }
2558     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
2559     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2560   }
2561   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
2562   ierr = PetscFree(partPoints);CHKERRQ(ierr);
2563   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2564   PetscFunctionReturn(0);
2565 }
2566 
2567 #undef __FUNCT__
2568 #define __FUNCT__ "DMPlexDistributeField"
2569 /*
2570   Input Parameters:
2571 . originalSection
2572 , originalVec
2573 
2574   Output Parameters:
2575 . newSection
2576 . newVec
2577 */
2578 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
2579 {
2580   PetscSF        fieldSF;
2581   PetscInt      *remoteOffsets, fieldSize;
2582   PetscScalar   *originalValues, *newValues;
2583   PetscErrorCode ierr;
2584 
2585   PetscFunctionBegin;
2586   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
2587 
2588   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
2589   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
2590   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
2591 
2592   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
2593   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
2594   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
2595   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2596   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
2597   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
2598   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
2599   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
2600   PetscFunctionReturn(0);
2601 }
2602 
2603 #undef __FUNCT__
2604 #define __FUNCT__ "DMPlexDistribute"
2605 /*@C
2606   DMPlexDistribute - Distributes the mesh and any associated sections.
2607 
2608   Not Collective
2609 
2610   Input Parameter:
2611 + dm  - The original DMPlex object
2612 . partitioner - The partitioning package, or NULL for the default
2613 - overlap - The overlap of partitions, 0 is the default
2614 
2615   Output Parameter:
2616 . parallelMesh - The distributed DMPlex object, or NULL
2617 
2618   Note: If the mesh was not distributed, the return value is NULL
2619 
2620   Level: intermediate
2621 
2622 .keywords: mesh, elements
2623 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
2624 @*/
2625 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
2626 {
2627   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
2628   MPI_Comm               comm;
2629   const PetscInt         height = 0;
2630   PetscInt               dim, numRemoteRanks;
2631   IS                     origCellPart,        cellPart,        part;
2632   PetscSection           origCellPartSection, cellPartSection, partSection;
2633   PetscSFNode           *remoteRanks;
2634   PetscSF                partSF, pointSF, coneSF;
2635   ISLocalToGlobalMapping renumbering;
2636   PetscSection           originalConeSection, newConeSection;
2637   PetscInt              *remoteOffsets;
2638   PetscInt              *cones, *newCones, newConesSize;
2639   PetscBool              flg;
2640   PetscMPIInt            rank, numProcs, p;
2641   PetscErrorCode         ierr;
2642 
2643   PetscFunctionBegin;
2644   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2645   PetscValidPointer(dmParallel,4);
2646 
2647   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2648   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2649   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2650   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
2651 
2652   *dmParallel = NULL;
2653   if (numProcs == 1) PetscFunctionReturn(0);
2654 
2655   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2656   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
2657   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
2658   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
2659   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
2660   if (!rank) numRemoteRanks = numProcs;
2661   else       numRemoteRanks = 0;
2662   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
2663   for (p = 0; p < numRemoteRanks; ++p) {
2664     remoteRanks[p].rank  = p;
2665     remoteRanks[p].index = 0;
2666   }
2667   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
2668   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
2669   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
2670   if (flg) {
2671     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
2672     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2673     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
2674     if (origCellPart) {
2675       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
2676       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2677       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
2678     }
2679     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
2680   }
2681   /* Close the partition over the mesh */
2682   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
2683   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
2684   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
2685   /* Create new mesh */
2686   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
2687   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
2688   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
2689   pmesh = (DM_Plex*) (*dmParallel)->data;
2690   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
2691   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
2692   if (flg) {
2693     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
2694     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2695     ierr = ISView(part, NULL);CHKERRQ(ierr);
2696     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
2697     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
2698     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
2699   }
2700   /* Distribute cone section */
2701   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
2702   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
2703   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
2704   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
2705   {
2706     PetscInt pStart, pEnd, p;
2707 
2708     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
2709     for (p = pStart; p < pEnd; ++p) {
2710       PetscInt coneSize;
2711       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
2712       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
2713     }
2714   }
2715   /* Communicate and renumber cones */
2716   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
2717   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
2718   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
2719   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2720   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2721   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
2722   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
2723   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
2724   if (flg) {
2725     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
2726     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2727     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
2728     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
2729     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
2730   }
2731   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
2732   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
2733   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2734   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
2735   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
2736   /* Create supports and stratify sieve */
2737   {
2738     PetscInt pStart, pEnd;
2739 
2740     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2741     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
2742   }
2743   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
2744   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
2745   /* Distribute Coordinates */
2746   {
2747     PetscSection originalCoordSection, newCoordSection;
2748     Vec          originalCoordinates, newCoordinates;
2749     const char  *name;
2750 
2751     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
2752     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
2753     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
2754     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
2755     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
2756     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
2757 
2758     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
2759     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
2760     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
2761   }
2762   /* Distribute labels */
2763   {
2764     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
2765     PetscInt numLabels = 0, l;
2766 
2767     /* Bcast number of labels */
2768     while (next) {
2769       ++numLabels; next = next->next;
2770     }
2771     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2772     next = mesh->labels;
2773     for (l = 0; l < numLabels; ++l) {
2774       DMLabel         newLabel;
2775       const PetscInt *partArray;
2776       char           *name;
2777       PetscInt       *stratumSizes = NULL, *points = NULL;
2778       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
2779       PetscInt        nameSize, s, p;
2780       PetscBool       isdepth;
2781       size_t          len = 0;
2782 
2783       /* Bcast name (could filter for no points) */
2784       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
2785       nameSize = len;
2786       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2787       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
2788       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
2789       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
2790       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
2791       if (isdepth) {            /* skip because "depth" is not distributed */
2792         ierr = PetscFree(name);CHKERRQ(ierr);
2793         if (!rank) next = next->next;
2794         continue;
2795       }
2796       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
2797       newLabel->name = name;
2798       /* Bcast numStrata (could filter for no points in stratum) */
2799       if (!rank) newLabel->numStrata = next->numStrata;
2800       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
2801       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
2802                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
2803                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
2804       /* Bcast stratumValues (could filter for no points in stratum) */
2805       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
2806       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2807       /* Find size on each process and Scatter */
2808       if (!rank) {
2809         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
2810         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
2811         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
2812         for (s = 0; s < next->numStrata; ++s) {
2813           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2814             const PetscInt point = next->points[p];
2815             PetscInt       proc;
2816 
2817             for (proc = 0; proc < numProcs; ++proc) {
2818               PetscInt dof, off, pPart;
2819 
2820               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2821               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2822               for (pPart = off; pPart < off+dof; ++pPart) {
2823                 if (partArray[pPart] == point) {
2824                   ++stratumSizes[proc*next->numStrata+s];
2825                   break;
2826                 }
2827               }
2828             }
2829           }
2830         }
2831         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
2832       }
2833       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
2834       /* Calculate stratumOffsets */
2835       newLabel->stratumOffsets[0] = 0;
2836       for (s = 0; s < newLabel->numStrata; ++s) {
2837         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
2838       }
2839       /* Pack points and Scatter */
2840       if (!rank) {
2841         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
2842         displs[0] = 0;
2843         for (p = 0; p < numProcs; ++p) {
2844           sendcnts[p] = 0;
2845           for (s = 0; s < next->numStrata; ++s) {
2846             sendcnts[p] += stratumSizes[p*next->numStrata+s];
2847           }
2848           offsets[p]  = displs[p];
2849           displs[p+1] = displs[p] + sendcnts[p];
2850         }
2851         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
2852         for (s = 0; s < next->numStrata; ++s) {
2853           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
2854             const PetscInt point = next->points[p];
2855             PetscInt       proc;
2856 
2857             for (proc = 0; proc < numProcs; ++proc) {
2858               PetscInt dof, off, pPart;
2859 
2860               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
2861               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
2862               for (pPart = off; pPart < off+dof; ++pPart) {
2863                 if (partArray[pPart] == point) {
2864                   points[offsets[proc]++] = point;
2865                   break;
2866                 }
2867               }
2868             }
2869           }
2870         }
2871       }
2872       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
2873       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
2874       ierr = PetscFree(points);CHKERRQ(ierr);
2875       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
2876       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
2877       /* Renumber points */
2878       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
2879       /* Sort points */
2880       for (s = 0; s < newLabel->numStrata; ++s) {
2881         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
2882       }
2883       /* Insert into list */
2884       if (newNext) newNext->next = newLabel;
2885       else pmesh->labels = newLabel;
2886       newNext = newLabel;
2887       if (!rank) next = next->next;
2888     }
2889   }
2890   /* Cleanup Partition */
2891   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
2892   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
2893   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
2894   ierr = ISDestroy(&part);CHKERRQ(ierr);
2895   /* Create point SF for parallel mesh */
2896   {
2897     const PetscInt *leaves;
2898     PetscSFNode    *remotePoints, *rowners, *lowners;
2899     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
2900     PetscInt        pStart, pEnd;
2901 
2902     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
2903     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
2904     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
2905     for (p=0; p<numRoots; p++) {
2906       rowners[p].rank  = -1;
2907       rowners[p].index = -1;
2908     }
2909     if (origCellPart) {
2910       /* Make sure cells in the original partition are not assigned to other procs */
2911       const PetscInt *origCells;
2912 
2913       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
2914       for (p = 0; p < numProcs; ++p) {
2915         PetscInt dof, off, d;
2916 
2917         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
2918         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
2919         for (d = off; d < off+dof; ++d) {
2920           rowners[origCells[d]].rank = p;
2921         }
2922       }
2923       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
2924     }
2925     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
2926     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
2927 
2928     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2929     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2930     for (p = 0; p < numLeaves; ++p) {
2931       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
2932         lowners[p].rank  = rank;
2933         lowners[p].index = leaves ? leaves[p] : p;
2934       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
2935         lowners[p].rank  = -2;
2936         lowners[p].index = -2;
2937       }
2938     }
2939     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
2940       rowners[p].rank  = -3;
2941       rowners[p].index = -3;
2942     }
2943     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
2944     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
2945     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2946     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
2947     for (p = 0; p < numLeaves; ++p) {
2948       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
2949       if (lowners[p].rank != rank) ++numGhostPoints;
2950     }
2951     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
2952     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
2953     for (p = 0, gp = 0; p < numLeaves; ++p) {
2954       if (lowners[p].rank != rank) {
2955         ghostPoints[gp]        = leaves ? leaves[p] : p;
2956         remotePoints[gp].rank  = lowners[p].rank;
2957         remotePoints[gp].index = lowners[p].index;
2958         ++gp;
2959       }
2960     }
2961     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
2962     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
2963     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
2964   }
2965   /* Cleanup */
2966   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
2967   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
2968   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
2969   PetscFunctionReturn(0);
2970 }
2971 
2972 #undef __FUNCT__
2973 #define __FUNCT__ "DMPlexInvertCells_Internal"
2974 /* This is to fix the tetrahedron orientation from TetGen */
2975 static PetscErrorCode DMPlexInvertCells_Internal(DM dm)
2976 {
2977   PetscInt       cStart, cEnd, c;
2978   PetscErrorCode ierr;
2979 
2980   PetscFunctionBegin;
2981   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2982   for (c = cStart; c < cEnd; ++c) {
2983     const PetscInt *cone;
2984     PetscInt        pa, pb;
2985 
2986     ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
2987     pa   = cone[0];
2988     pb   = cone[1];
2989     ierr = DMPlexInsertCone(dm, c, 0, pb);CHKERRQ(ierr);
2990     ierr = DMPlexInsertCone(dm, c, 1, pa);CHKERRQ(ierr);
2991   }
2992   PetscFunctionReturn(0);
2993 }
2994 
2995 #if defined(PETSC_HAVE_TRIANGLE)
2996 #include <triangle.h>
2997 
2998 #undef __FUNCT__
2999 #define __FUNCT__ "InitInput_Triangle"
3000 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
3001 {
3002   PetscFunctionBegin;
3003   inputCtx->numberofpoints             = 0;
3004   inputCtx->numberofpointattributes    = 0;
3005   inputCtx->pointlist                  = NULL;
3006   inputCtx->pointattributelist         = NULL;
3007   inputCtx->pointmarkerlist            = NULL;
3008   inputCtx->numberofsegments           = 0;
3009   inputCtx->segmentlist                = NULL;
3010   inputCtx->segmentmarkerlist          = NULL;
3011   inputCtx->numberoftriangleattributes = 0;
3012   inputCtx->trianglelist               = NULL;
3013   inputCtx->numberofholes              = 0;
3014   inputCtx->holelist                   = NULL;
3015   inputCtx->numberofregions            = 0;
3016   inputCtx->regionlist                 = NULL;
3017   PetscFunctionReturn(0);
3018 }
3019 
3020 #undef __FUNCT__
3021 #define __FUNCT__ "InitOutput_Triangle"
3022 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
3023 {
3024   PetscFunctionBegin;
3025   outputCtx->numberofpoints        = 0;
3026   outputCtx->pointlist             = NULL;
3027   outputCtx->pointattributelist    = NULL;
3028   outputCtx->pointmarkerlist       = NULL;
3029   outputCtx->numberoftriangles     = 0;
3030   outputCtx->trianglelist          = NULL;
3031   outputCtx->triangleattributelist = NULL;
3032   outputCtx->neighborlist          = NULL;
3033   outputCtx->segmentlist           = NULL;
3034   outputCtx->segmentmarkerlist     = NULL;
3035   outputCtx->numberofedges         = 0;
3036   outputCtx->edgelist              = NULL;
3037   outputCtx->edgemarkerlist        = NULL;
3038   PetscFunctionReturn(0);
3039 }
3040 
3041 #undef __FUNCT__
3042 #define __FUNCT__ "FiniOutput_Triangle"
3043 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
3044 {
3045   PetscFunctionBegin;
3046   free(outputCtx->pointmarkerlist);
3047   free(outputCtx->edgelist);
3048   free(outputCtx->edgemarkerlist);
3049   free(outputCtx->trianglelist);
3050   free(outputCtx->neighborlist);
3051   PetscFunctionReturn(0);
3052 }
3053 
3054 #undef __FUNCT__
3055 #define __FUNCT__ "DMPlexGenerate_Triangle"
3056 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
3057 {
3058   MPI_Comm             comm;
3059   PetscInt             dim              = 2;
3060   const PetscBool      createConvexHull = PETSC_FALSE;
3061   const PetscBool      constrained      = PETSC_FALSE;
3062   struct triangulateio in;
3063   struct triangulateio out;
3064   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
3065   PetscMPIInt          rank;
3066   PetscErrorCode       ierr;
3067 
3068   PetscFunctionBegin;
3069   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3070   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3071   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3072   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3073   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3074 
3075   in.numberofpoints = vEnd - vStart;
3076   if (in.numberofpoints > 0) {
3077     PetscSection coordSection;
3078     Vec          coordinates;
3079     PetscScalar *array;
3080 
3081     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3082     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3083     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3084     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3085     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3086     for (v = vStart; v < vEnd; ++v) {
3087       const PetscInt idx = v - vStart;
3088       PetscInt       off, d;
3089 
3090       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3091       for (d = 0; d < dim; ++d) {
3092         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3093       }
3094       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3095     }
3096     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3097   }
3098   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
3099   in.numberofsegments = eEnd - eStart;
3100   if (in.numberofsegments > 0) {
3101     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
3102     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
3103     for (e = eStart; e < eEnd; ++e) {
3104       const PetscInt  idx = e - eStart;
3105       const PetscInt *cone;
3106 
3107       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
3108 
3109       in.segmentlist[idx*2+0] = cone[0] - vStart;
3110       in.segmentlist[idx*2+1] = cone[1] - vStart;
3111 
3112       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
3113     }
3114   }
3115 #if 0 /* Do not currently support holes */
3116   PetscReal *holeCoords;
3117   PetscInt   h, d;
3118 
3119   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3120   if (in.numberofholes > 0) {
3121     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3122     for (h = 0; h < in.numberofholes; ++h) {
3123       for (d = 0; d < dim; ++d) {
3124         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3125       }
3126     }
3127   }
3128 #endif
3129   if (!rank) {
3130     char args[32];
3131 
3132     /* Take away 'Q' for verbose output */
3133     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3134     if (createConvexHull) {
3135       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
3136     }
3137     if (constrained) {
3138       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
3139     }
3140     triangulate(args, &in, &out, NULL);
3141   }
3142   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3143   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3144   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3145   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3146   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
3147 
3148   {
3149     const PetscInt numCorners  = 3;
3150     const PetscInt numCells    = out.numberoftriangles;
3151     const PetscInt numVertices = out.numberofpoints;
3152     const int     *cells      = out.trianglelist;
3153     const double  *meshCoords = out.pointlist;
3154 
3155     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3156     /* Set labels */
3157     for (v = 0; v < numVertices; ++v) {
3158       if (out.pointmarkerlist[v]) {
3159         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3160       }
3161     }
3162     if (interpolate) {
3163       for (e = 0; e < out.numberofedges; e++) {
3164         if (out.edgemarkerlist[e]) {
3165           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3166           const PetscInt *edges;
3167           PetscInt        numEdges;
3168 
3169           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3170           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3171           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3172           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3173         }
3174       }
3175     }
3176     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3177   }
3178 #if 0 /* Do not currently support holes */
3179   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3180 #endif
3181   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3182   PetscFunctionReturn(0);
3183 }
3184 
3185 #undef __FUNCT__
3186 #define __FUNCT__ "DMPlexRefine_Triangle"
3187 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
3188 {
3189   MPI_Comm             comm;
3190   PetscInt             dim  = 2;
3191   struct triangulateio in;
3192   struct triangulateio out;
3193   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3194   PetscMPIInt          rank;
3195   PetscErrorCode       ierr;
3196 
3197   PetscFunctionBegin;
3198   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3199   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3200   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
3201   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
3202   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3203   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3204   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3205 
3206   in.numberofpoints = vEnd - vStart;
3207   if (in.numberofpoints > 0) {
3208     PetscSection coordSection;
3209     Vec          coordinates;
3210     PetscScalar *array;
3211 
3212     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
3213     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
3214     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3215     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3216     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3217     for (v = vStart; v < vEnd; ++v) {
3218       const PetscInt idx = v - vStart;
3219       PetscInt       off, d;
3220 
3221       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3222       for (d = 0; d < dim; ++d) {
3223         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3224       }
3225       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3226     }
3227     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3228   }
3229   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3230 
3231   in.numberofcorners   = 3;
3232   in.numberoftriangles = cEnd - cStart;
3233 
3234   in.trianglearealist  = (double*) maxVolumes;
3235   if (in.numberoftriangles > 0) {
3236     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
3237     for (c = cStart; c < cEnd; ++c) {
3238       const PetscInt idx      = c - cStart;
3239       PetscInt      *closure = NULL;
3240       PetscInt       closureSize;
3241 
3242       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3243       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
3244       for (v = 0; v < 3; ++v) {
3245         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
3246       }
3247       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3248     }
3249   }
3250   /* TODO: Segment markers are missing on input */
3251 #if 0 /* Do not currently support holes */
3252   PetscReal *holeCoords;
3253   PetscInt   h, d;
3254 
3255   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
3256   if (in.numberofholes > 0) {
3257     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
3258     for (h = 0; h < in.numberofholes; ++h) {
3259       for (d = 0; d < dim; ++d) {
3260         in.holelist[h*dim+d] = holeCoords[h*dim+d];
3261       }
3262     }
3263   }
3264 #endif
3265   if (!rank) {
3266     char args[32];
3267 
3268     /* Take away 'Q' for verbose output */
3269     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
3270     triangulate(args, &in, &out, NULL);
3271   }
3272   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
3273   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
3274   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
3275   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
3276   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
3277 
3278   {
3279     const PetscInt numCorners  = 3;
3280     const PetscInt numCells    = out.numberoftriangles;
3281     const PetscInt numVertices = out.numberofpoints;
3282     const int     *cells      = out.trianglelist;
3283     const double  *meshCoords = out.pointlist;
3284     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3285 
3286     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3287     /* Set labels */
3288     for (v = 0; v < numVertices; ++v) {
3289       if (out.pointmarkerlist[v]) {
3290         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3291       }
3292     }
3293     if (interpolate) {
3294       PetscInt e;
3295 
3296       for (e = 0; e < out.numberofedges; e++) {
3297         if (out.edgemarkerlist[e]) {
3298           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3299           const PetscInt *edges;
3300           PetscInt        numEdges;
3301 
3302           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3303           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3304           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3305           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3306         }
3307       }
3308     }
3309     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3310   }
3311 #if 0 /* Do not currently support holes */
3312   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
3313 #endif
3314   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
3315   PetscFunctionReturn(0);
3316 }
3317 #endif
3318 
3319 #if defined(PETSC_HAVE_TETGEN)
3320 #include <tetgen.h>
3321 #undef __FUNCT__
3322 #define __FUNCT__ "DMPlexGenerate_Tetgen"
3323 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
3324 {
3325   MPI_Comm       comm;
3326   const PetscInt dim  = 3;
3327   ::tetgenio     in;
3328   ::tetgenio     out;
3329   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
3330   PetscMPIInt    rank;
3331   PetscErrorCode ierr;
3332 
3333   PetscFunctionBegin;
3334   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3335   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3336   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3337   in.numberofpoints = vEnd - vStart;
3338   if (in.numberofpoints > 0) {
3339     PetscSection coordSection;
3340     Vec          coordinates;
3341     PetscScalar *array;
3342 
3343     in.pointlist       = new double[in.numberofpoints*dim];
3344     in.pointmarkerlist = new int[in.numberofpoints];
3345 
3346     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3347     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3348     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3349     for (v = vStart; v < vEnd; ++v) {
3350       const PetscInt idx = v - vStart;
3351       PetscInt       off, d;
3352 
3353       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3354       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3355       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3356     }
3357     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3358   }
3359   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3360 
3361   in.numberoffacets = fEnd - fStart;
3362   if (in.numberoffacets > 0) {
3363     in.facetlist       = new tetgenio::facet[in.numberoffacets];
3364     in.facetmarkerlist = new int[in.numberoffacets];
3365     for (f = fStart; f < fEnd; ++f) {
3366       const PetscInt idx     = f - fStart;
3367       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
3368 
3369       in.facetlist[idx].numberofpolygons = 1;
3370       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
3371       in.facetlist[idx].numberofholes    = 0;
3372       in.facetlist[idx].holelist         = NULL;
3373 
3374       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3375       for (p = 0; p < numPoints*2; p += 2) {
3376         const PetscInt point = points[p];
3377         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3378       }
3379 
3380       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
3381       poly->numberofvertices = numVertices;
3382       poly->vertexlist       = new int[poly->numberofvertices];
3383       for (v = 0; v < numVertices; ++v) {
3384         const PetscInt vIdx = points[v] - vStart;
3385         poly->vertexlist[v] = vIdx;
3386       }
3387       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
3388       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3389     }
3390   }
3391   if (!rank) {
3392     char args[32];
3393 
3394     /* Take away 'Q' for verbose output */
3395     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
3396     ::tetrahedralize(args, &in, &out);
3397   }
3398   {
3399     const PetscInt numCorners  = 4;
3400     const PetscInt numCells    = out.numberoftetrahedra;
3401     const PetscInt numVertices = out.numberofpoints;
3402     const int     *cells      = out.tetrahedronlist;
3403     const double  *meshCoords = out.pointlist;
3404 
3405     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3406     ierr = DMPlexInvertCells_Internal(*dm);CHKERRQ(ierr);
3407     /* Set labels */
3408     for (v = 0; v < numVertices; ++v) {
3409       if (out.pointmarkerlist[v]) {
3410         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3411       }
3412     }
3413     if (interpolate) {
3414       PetscInt e;
3415 
3416       for (e = 0; e < out.numberofedges; e++) {
3417         if (out.edgemarkerlist[e]) {
3418           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3419           const PetscInt *edges;
3420           PetscInt        numEdges;
3421 
3422           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3423           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3424           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3425           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3426         }
3427       }
3428       for (f = 0; f < out.numberoftrifaces; f++) {
3429         if (out.trifacemarkerlist[f]) {
3430           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3431           const PetscInt *faces;
3432           PetscInt        numFaces;
3433 
3434           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3435           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3436           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3437           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3438         }
3439       }
3440     }
3441     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3442   }
3443   PetscFunctionReturn(0);
3444 }
3445 
3446 #undef __FUNCT__
3447 #define __FUNCT__ "DMPlexRefine_Tetgen"
3448 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
3449 {
3450   MPI_Comm       comm;
3451   const PetscInt dim  = 3;
3452   ::tetgenio     in;
3453   ::tetgenio     out;
3454   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3455   PetscMPIInt    rank;
3456   PetscErrorCode ierr;
3457 
3458   PetscFunctionBegin;
3459   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3460   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3461   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3462   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3463   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3464 
3465   in.numberofpoints = vEnd - vStart;
3466   if (in.numberofpoints > 0) {
3467     PetscSection coordSection;
3468     Vec          coordinates;
3469     PetscScalar *array;
3470 
3471     in.pointlist       = new double[in.numberofpoints*dim];
3472     in.pointmarkerlist = new int[in.numberofpoints];
3473 
3474     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3475     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3476     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3477     for (v = vStart; v < vEnd; ++v) {
3478       const PetscInt idx = v - vStart;
3479       PetscInt       off, d;
3480 
3481       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3482       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
3483       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
3484     }
3485     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3486   }
3487   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3488 
3489   in.numberofcorners       = 4;
3490   in.numberoftetrahedra    = cEnd - cStart;
3491   in.tetrahedronvolumelist = (double*) maxVolumes;
3492   if (in.numberoftetrahedra > 0) {
3493     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
3494     for (c = cStart; c < cEnd; ++c) {
3495       const PetscInt idx      = c - cStart;
3496       PetscInt      *closure = NULL;
3497       PetscInt       closureSize;
3498 
3499       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3500       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3501       for (v = 0; v < 4; ++v) {
3502         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3503       }
3504       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3505     }
3506   }
3507   /* TODO: Put in boundary faces with markers */
3508   if (!rank) {
3509     char args[32];
3510 
3511     /* Take away 'Q' for verbose output */
3512     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
3513     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
3514     ::tetrahedralize(args, &in, &out);
3515   }
3516   in.tetrahedronvolumelist = NULL;
3517 
3518   {
3519     const PetscInt numCorners  = 4;
3520     const PetscInt numCells    = out.numberoftetrahedra;
3521     const PetscInt numVertices = out.numberofpoints;
3522     const int     *cells      = out.tetrahedronlist;
3523     const double  *meshCoords = out.pointlist;
3524     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3525 
3526     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3527     ierr = DMPlexInvertCells_Internal(*dmRefined);CHKERRQ(ierr);
3528     /* Set labels */
3529     for (v = 0; v < numVertices; ++v) {
3530       if (out.pointmarkerlist[v]) {
3531         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
3532       }
3533     }
3534     if (interpolate) {
3535       PetscInt e, f;
3536 
3537       for (e = 0; e < out.numberofedges; e++) {
3538         if (out.edgemarkerlist[e]) {
3539           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
3540           const PetscInt *edges;
3541           PetscInt        numEdges;
3542 
3543           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3544           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3545           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
3546           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3547         }
3548       }
3549       for (f = 0; f < out.numberoftrifaces; f++) {
3550         if (out.trifacemarkerlist[f]) {
3551           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
3552           const PetscInt *faces;
3553           PetscInt        numFaces;
3554 
3555           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3556           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3557           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
3558           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3559         }
3560       }
3561     }
3562     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3563   }
3564   PetscFunctionReturn(0);
3565 }
3566 #endif
3567 
3568 #if defined(PETSC_HAVE_CTETGEN)
3569 #include "ctetgen.h"
3570 
3571 #undef __FUNCT__
3572 #define __FUNCT__ "DMPlexGenerate_CTetgen"
3573 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
3574 {
3575   MPI_Comm       comm;
3576   const PetscInt dim  = 3;
3577   PLC           *in, *out;
3578   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
3579   PetscMPIInt    rank;
3580   PetscErrorCode ierr;
3581 
3582   PetscFunctionBegin;
3583   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
3584   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3585   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3586   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
3587   ierr = PLCCreate(&in);CHKERRQ(ierr);
3588   ierr = PLCCreate(&out);CHKERRQ(ierr);
3589 
3590   in->numberofpoints = vEnd - vStart;
3591   if (in->numberofpoints > 0) {
3592     PetscSection coordSection;
3593     Vec          coordinates;
3594     PetscScalar *array;
3595 
3596     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3597     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3598     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
3599     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
3600     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3601     for (v = vStart; v < vEnd; ++v) {
3602       const PetscInt idx = v - vStart;
3603       PetscInt       off, d, m;
3604 
3605       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3606       for (d = 0; d < dim; ++d) {
3607         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3608       }
3609       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
3610 
3611       in->pointmarkerlist[idx] = (int) m;
3612     }
3613     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3614   }
3615   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
3616 
3617   in->numberoffacets = fEnd - fStart;
3618   if (in->numberoffacets > 0) {
3619     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
3620     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
3621     for (f = fStart; f < fEnd; ++f) {
3622       const PetscInt idx     = f - fStart;
3623       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
3624       polygon       *poly;
3625 
3626       in->facetlist[idx].numberofpolygons = 1;
3627 
3628       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
3629 
3630       in->facetlist[idx].numberofholes    = 0;
3631       in->facetlist[idx].holelist         = NULL;
3632 
3633       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3634       for (p = 0; p < numPoints*2; p += 2) {
3635         const PetscInt point = points[p];
3636         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
3637       }
3638 
3639       poly                   = in->facetlist[idx].polygonlist;
3640       poly->numberofvertices = numVertices;
3641       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
3642       for (v = 0; v < numVertices; ++v) {
3643         const PetscInt vIdx = points[v] - vStart;
3644         poly->vertexlist[v] = vIdx;
3645       }
3646       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
3647       in->facetmarkerlist[idx] = (int) m;
3648       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
3649     }
3650   }
3651   if (!rank) {
3652     TetGenOpts t;
3653 
3654     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3655     t.in        = boundary; /* Should go away */
3656     t.plc       = 1;
3657     t.quality   = 1;
3658     t.edgesout  = 1;
3659     t.zeroindex = 1;
3660     t.quiet     = 1;
3661     t.verbose   = verbose;
3662     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
3663     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3664   }
3665   {
3666     const PetscInt numCorners  = 4;
3667     const PetscInt numCells    = out->numberoftetrahedra;
3668     const PetscInt numVertices = out->numberofpoints;
3669     const int     *cells      = out->tetrahedronlist;
3670     const double  *meshCoords = out->pointlist;
3671 
3672     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dm);CHKERRQ(ierr);
3673     ierr = DMPlexInvertCells_Internal(*dm);CHKERRQ(ierr);
3674     /* Set labels */
3675     for (v = 0; v < numVertices; ++v) {
3676       if (out->pointmarkerlist[v]) {
3677         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3678       }
3679     }
3680     if (interpolate) {
3681       PetscInt e;
3682 
3683       for (e = 0; e < out->numberofedges; e++) {
3684         if (out->edgemarkerlist[e]) {
3685           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3686           const PetscInt *edges;
3687           PetscInt        numEdges;
3688 
3689           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3690           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3691           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3692           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3693         }
3694       }
3695       for (f = 0; f < out->numberoftrifaces; f++) {
3696         if (out->trifacemarkerlist[f]) {
3697           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3698           const PetscInt *faces;
3699           PetscInt        numFaces;
3700 
3701           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3702           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3703           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3704           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3705         }
3706       }
3707     }
3708     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
3709   }
3710 
3711   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3712   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3713   PetscFunctionReturn(0);
3714 }
3715 
3716 #undef __FUNCT__
3717 #define __FUNCT__ "DMPlexRefine_CTetgen"
3718 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
3719 {
3720   MPI_Comm       comm;
3721   const PetscInt dim  = 3;
3722   PLC           *in, *out;
3723   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
3724   PetscMPIInt    rank;
3725   PetscErrorCode ierr;
3726 
3727   PetscFunctionBegin;
3728   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3729   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
3730   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3731   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3732   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
3733   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3734   ierr = PLCCreate(&in);CHKERRQ(ierr);
3735   ierr = PLCCreate(&out);CHKERRQ(ierr);
3736 
3737   in->numberofpoints = vEnd - vStart;
3738   if (in->numberofpoints > 0) {
3739     PetscSection coordSection;
3740     Vec          coordinates;
3741     PetscScalar *array;
3742 
3743     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
3744     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
3745     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3746     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3747     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
3748     for (v = vStart; v < vEnd; ++v) {
3749       const PetscInt idx = v - vStart;
3750       PetscInt       off, d, m;
3751 
3752       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3753       for (d = 0; d < dim; ++d) {
3754         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
3755       }
3756       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
3757 
3758       in->pointmarkerlist[idx] = (int) m;
3759     }
3760     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
3761   }
3762   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3763 
3764   in->numberofcorners       = 4;
3765   in->numberoftetrahedra    = cEnd - cStart;
3766   in->tetrahedronvolumelist = maxVolumes;
3767   if (in->numberoftetrahedra > 0) {
3768     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
3769     for (c = cStart; c < cEnd; ++c) {
3770       const PetscInt idx      = c - cStart;
3771       PetscInt      *closure = NULL;
3772       PetscInt       closureSize;
3773 
3774       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3775       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
3776       for (v = 0; v < 4; ++v) {
3777         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
3778       }
3779       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3780     }
3781   }
3782   if (!rank) {
3783     TetGenOpts t;
3784 
3785     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
3786 
3787     t.in        = dm; /* Should go away */
3788     t.refine    = 1;
3789     t.varvolume = 1;
3790     t.quality   = 1;
3791     t.edgesout  = 1;
3792     t.zeroindex = 1;
3793     t.quiet     = 1;
3794     t.verbose   = verbose; /* Change this */
3795 
3796     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
3797     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
3798   }
3799   {
3800     const PetscInt numCorners  = 4;
3801     const PetscInt numCells    = out->numberoftetrahedra;
3802     const PetscInt numVertices = out->numberofpoints;
3803     const int     *cells       = out->tetrahedronlist;
3804     const double  *meshCoords  = out->pointlist;
3805     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
3806 
3807     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, dim, meshCoords, dmRefined);CHKERRQ(ierr);
3808     ierr = DMPlexInvertCells_Internal(*dmRefined);CHKERRQ(ierr);
3809     /* Set labels */
3810     for (v = 0; v < numVertices; ++v) {
3811       if (out->pointmarkerlist[v]) {
3812         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
3813       }
3814     }
3815     if (interpolate) {
3816       PetscInt e, f;
3817 
3818       for (e = 0; e < out->numberofedges; e++) {
3819         if (out->edgemarkerlist[e]) {
3820           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
3821           const PetscInt *edges;
3822           PetscInt        numEdges;
3823 
3824           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3825           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
3826           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
3827           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
3828         }
3829       }
3830       for (f = 0; f < out->numberoftrifaces; f++) {
3831         if (out->trifacemarkerlist[f]) {
3832           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
3833           const PetscInt *faces;
3834           PetscInt        numFaces;
3835 
3836           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3837           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
3838           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
3839           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
3840         }
3841       }
3842     }
3843     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
3844   }
3845   ierr = PLCDestroy(&in);CHKERRQ(ierr);
3846   ierr = PLCDestroy(&out);CHKERRQ(ierr);
3847   PetscFunctionReturn(0);
3848 }
3849 #endif
3850 
3851 #undef __FUNCT__
3852 #define __FUNCT__ "DMPlexGenerate"
3853 /*@C
3854   DMPlexGenerate - Generates a mesh.
3855 
3856   Not Collective
3857 
3858   Input Parameters:
3859 + boundary - The DMPlex boundary object
3860 . name - The mesh generation package name
3861 - interpolate - Flag to create intermediate mesh elements
3862 
3863   Output Parameter:
3864 . mesh - The DMPlex object
3865 
3866   Level: intermediate
3867 
3868 .keywords: mesh, elements
3869 .seealso: DMPlexCreate(), DMRefine()
3870 @*/
3871 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
3872 {
3873   PetscInt       dim;
3874   char           genname[1024];
3875   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
3876   PetscErrorCode ierr;
3877 
3878   PetscFunctionBegin;
3879   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
3880   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
3881   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
3882   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
3883   if (flg) name = genname;
3884   if (name) {
3885     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
3886     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
3887     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
3888   }
3889   switch (dim) {
3890   case 1:
3891     if (!name || isTriangle) {
3892 #if defined(PETSC_HAVE_TRIANGLE)
3893       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
3894 #else
3895       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
3896 #endif
3897     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
3898     break;
3899   case 2:
3900     if (!name || isCTetgen) {
3901 #if defined(PETSC_HAVE_CTETGEN)
3902       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
3903 #else
3904       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
3905 #endif
3906     } else if (isTetgen) {
3907 #if defined(PETSC_HAVE_TETGEN)
3908       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
3909 #else
3910       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
3911 #endif
3912     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
3913     break;
3914   default:
3915     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
3916   }
3917   PetscFunctionReturn(0);
3918 }
3919 
3920 typedef PetscInt CellRefiner;
3921 
3922 #undef __FUNCT__
3923 #define __FUNCT__ "GetDepthStart_Private"
3924 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
3925 {
3926   PetscFunctionBegin;
3927   if (cStart) *cStart = 0;
3928   if (vStart) *vStart = depthSize[depth];
3929   if (fStart) *fStart = depthSize[depth] + depthSize[0];
3930   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
3931   PetscFunctionReturn(0);
3932 }
3933 
3934 #undef __FUNCT__
3935 #define __FUNCT__ "GetDepthEnd_Private"
3936 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
3937 {
3938   PetscFunctionBegin;
3939   if (cEnd) *cEnd = depthSize[depth];
3940   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
3941   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
3942   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
3943   PetscFunctionReturn(0);
3944 }
3945 
3946 #undef __FUNCT__
3947 #define __FUNCT__ "CellRefinerGetSizes"
3948 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
3949 {
3950   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
3951   PetscErrorCode ierr;
3952 
3953   PetscFunctionBegin;
3954   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3955   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3956   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3957   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
3958   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
3959   switch (refiner) {
3960   case 1:
3961     /* Simplicial 2D */
3962     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
3963     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
3964     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
3965     break;
3966   case 3:
3967     /* Hybrid 2D */
3968     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
3969     cMax = PetscMin(cEnd, cMax);
3970     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
3971     fMax         = PetscMin(fEnd, fMax);
3972     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
3973     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 */
3974     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
3975     break;
3976   case 2:
3977     /* Hex 2D */
3978     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
3979     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
3980     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
3981     break;
3982   default:
3983     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
3984   }
3985   PetscFunctionReturn(0);
3986 }
3987 
3988 #undef __FUNCT__
3989 #define __FUNCT__ "CellRefinerSetConeSizes"
3990 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
3991 {
3992   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
3993   PetscErrorCode ierr;
3994 
3995   PetscFunctionBegin;
3996   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3997   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3998   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
3999   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4000   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4001   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4002   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4003   switch (refiner) {
4004   case 1:
4005     /* Simplicial 2D */
4006     /* All cells have 3 faces */
4007     for (c = cStart; c < cEnd; ++c) {
4008       for (r = 0; r < 4; ++r) {
4009         const PetscInt newp = (c - cStart)*4 + r;
4010 
4011         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4012       }
4013     }
4014     /* Split faces have 2 vertices and the same cells as the parent */
4015     for (f = fStart; f < fEnd; ++f) {
4016       for (r = 0; r < 2; ++r) {
4017         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4018         PetscInt       size;
4019 
4020         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4021         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4022         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4023       }
4024     }
4025     /* Interior faces have 2 vertices and 2 cells */
4026     for (c = cStart; c < cEnd; ++c) {
4027       for (r = 0; r < 3; ++r) {
4028         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4029 
4030         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4031         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4032       }
4033     }
4034     /* Old vertices have identical supports */
4035     for (v = vStart; v < vEnd; ++v) {
4036       const PetscInt newp = vStartNew + (v - vStart);
4037       PetscInt       size;
4038 
4039       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4040       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4041     }
4042     /* Face vertices have 2 + cells*2 supports */
4043     for (f = fStart; f < fEnd; ++f) {
4044       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4045       PetscInt       size;
4046 
4047       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4048       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
4049     }
4050     break;
4051   case 2:
4052     /* Hex 2D */
4053     /* All cells have 4 faces */
4054     for (c = cStart; c < cEnd; ++c) {
4055       for (r = 0; r < 4; ++r) {
4056         const PetscInt newp = (c - cStart)*4 + r;
4057 
4058         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4059       }
4060     }
4061     /* Split faces have 2 vertices and the same cells as the parent */
4062     for (f = fStart; f < fEnd; ++f) {
4063       for (r = 0; r < 2; ++r) {
4064         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4065         PetscInt       size;
4066 
4067         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4068         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4069         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4070       }
4071     }
4072     /* Interior faces have 2 vertices and 2 cells */
4073     for (c = cStart; c < cEnd; ++c) {
4074       for (r = 0; r < 4; ++r) {
4075         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4076 
4077         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4078         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4079       }
4080     }
4081     /* Old vertices have identical supports */
4082     for (v = vStart; v < vEnd; ++v) {
4083       const PetscInt newp = vStartNew + (v - vStart);
4084       PetscInt       size;
4085 
4086       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4087       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4088     }
4089     /* Face vertices have 2 + cells supports */
4090     for (f = fStart; f < fEnd; ++f) {
4091       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4092       PetscInt       size;
4093 
4094       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4095       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
4096     }
4097     /* Cell vertices have 4 supports */
4098     for (c = cStart; c < cEnd; ++c) {
4099       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4100 
4101       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
4102     }
4103     break;
4104   case 3:
4105     /* Hybrid 2D */
4106     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4107     cMax = PetscMin(cEnd, cMax);
4108     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4109     fMax = PetscMin(fEnd, fMax);
4110     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4111     /* Interior cells have 3 faces */
4112     for (c = cStart; c < cMax; ++c) {
4113       for (r = 0; r < 4; ++r) {
4114         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
4115 
4116         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
4117       }
4118     }
4119     /* Hybrid cells have 4 faces */
4120     for (c = cMax; c < cEnd; ++c) {
4121       for (r = 0; r < 2; ++r) {
4122         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
4123 
4124         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
4125       }
4126     }
4127     /* Interior split faces have 2 vertices and the same cells as the parent */
4128     for (f = fStart; f < fMax; ++f) {
4129       for (r = 0; r < 2; ++r) {
4130         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
4131         PetscInt       size;
4132 
4133         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4134         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4135         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4136       }
4137     }
4138     /* Interior cell faces have 2 vertices and 2 cells */
4139     for (c = cStart; c < cMax; ++c) {
4140       for (r = 0; r < 3; ++r) {
4141         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4142 
4143         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4144         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4145       }
4146     }
4147     /* Hybrid faces have 2 vertices and the same cells */
4148     for (f = fMax; f < fEnd; ++f) {
4149       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4150       PetscInt       size;
4151 
4152       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4153       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4154       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4155     }
4156     /* Hybrid cell faces have 2 vertices and 2 cells */
4157     for (c = cMax; c < cEnd; ++c) {
4158       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4159 
4160       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
4161       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
4162     }
4163     /* Old vertices have identical supports */
4164     for (v = vStart; v < vEnd; ++v) {
4165       const PetscInt newp = vStartNew + (v - vStart);
4166       PetscInt       size;
4167 
4168       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4169       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
4170     }
4171     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4172     for (f = fStart; f < fMax; ++f) {
4173       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
4174       const PetscInt *support;
4175       PetscInt       size, newSize = 2, s;
4176 
4177       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4178       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4179       for (s = 0; s < size; ++s) {
4180         if (support[s] >= cMax) newSize += 1;
4181         else newSize += 2;
4182       }
4183       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
4184     }
4185     break;
4186   default:
4187     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4188   }
4189   PetscFunctionReturn(0);
4190 }
4191 
4192 #undef __FUNCT__
4193 #define __FUNCT__ "CellRefinerSetCones"
4194 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4195 {
4196   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;
4197   PetscInt       maxSupportSize, *supportRef;
4198   PetscErrorCode ierr;
4199 
4200   PetscFunctionBegin;
4201   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4202   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4203   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
4204   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4205   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4206   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
4207   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
4208   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
4209   switch (refiner) {
4210   case 1:
4211     /* Simplicial 2D */
4212     /*
4213      2
4214      |\
4215      | \
4216      |  \
4217      |   \
4218      | C  \
4219      |     \
4220      |      \
4221      2---1---1
4222      |\  D  / \
4223      | 2   0   \
4224      |A \ /  B  \
4225      0---0-------1
4226      */
4227     /* All cells have 3 faces */
4228     for (c = cStart; c < cEnd; ++c) {
4229       const PetscInt  newp = cStartNew + (c - cStart)*4;
4230       const PetscInt *cone, *ornt;
4231       PetscInt        coneNew[3], orntNew[3];
4232 
4233       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4234       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4235       /* A triangle */
4236       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4237       orntNew[0] = ornt[0];
4238       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4239       orntNew[1] = -2;
4240       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4241       orntNew[2] = ornt[2];
4242       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4243       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4244 #if 1
4245       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);
4246       for (p = 0; p < 3; ++p) {
4247         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);
4248       }
4249 #endif
4250       /* B triangle */
4251       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4252       orntNew[0] = ornt[0];
4253       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4254       orntNew[1] = ornt[1];
4255       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4256       orntNew[2] = -2;
4257       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4258       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4259 #if 1
4260       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);
4261       for (p = 0; p < 3; ++p) {
4262         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);
4263       }
4264 #endif
4265       /* C triangle */
4266       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4267       orntNew[0] = -2;
4268       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4269       orntNew[1] = ornt[1];
4270       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4271       orntNew[2] = ornt[2];
4272       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4273       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4274 #if 1
4275       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);
4276       for (p = 0; p < 3; ++p) {
4277         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);
4278       }
4279 #endif
4280       /* D triangle */
4281       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
4282       orntNew[0] = 0;
4283       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
4284       orntNew[1] = 0;
4285       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
4286       orntNew[2] = 0;
4287       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4288       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4289 #if 1
4290       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);
4291       for (p = 0; p < 3; ++p) {
4292         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);
4293       }
4294 #endif
4295     }
4296     /* Split faces have 2 vertices and the same cells as the parent */
4297     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4298     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4299     for (f = fStart; f < fEnd; ++f) {
4300       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4301 
4302       for (r = 0; r < 2; ++r) {
4303         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4304         const PetscInt *cone, *support;
4305         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4306 
4307         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4308         coneNew[0]       = vStartNew + (cone[0] - vStart);
4309         coneNew[1]       = vStartNew + (cone[1] - vStart);
4310         coneNew[(r+1)%2] = newv;
4311         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4312 #if 1
4313         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4314         for (p = 0; p < 2; ++p) {
4315           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);
4316         }
4317 #endif
4318         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4319         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4320         for (s = 0; s < supportSize; ++s) {
4321           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4322           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4323           for (c = 0; c < coneSize; ++c) {
4324             if (cone[c] == f) break;
4325           }
4326           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4327         }
4328         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4329 #if 1
4330         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4331         for (p = 0; p < supportSize; ++p) {
4332           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);
4333         }
4334 #endif
4335       }
4336     }
4337     /* Interior faces have 2 vertices and 2 cells */
4338     for (c = cStart; c < cEnd; ++c) {
4339       const PetscInt *cone;
4340 
4341       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4342       for (r = 0; r < 3; ++r) {
4343         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
4344         PetscInt       coneNew[2];
4345         PetscInt       supportNew[2];
4346 
4347         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4348         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4349         ierr       = DMPlexSetCone(rdm, newp, coneNew);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 ((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);
4354         }
4355 #endif
4356         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4357         supportNew[1] = (c - cStart)*4 + 3;
4358         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4359 #if 1
4360         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4361         for (p = 0; p < 2; ++p) {
4362           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);
4363         }
4364 #endif
4365       }
4366     }
4367     /* Old vertices have identical supports */
4368     for (v = vStart; v < vEnd; ++v) {
4369       const PetscInt  newp = vStartNew + (v - vStart);
4370       const PetscInt *support, *cone;
4371       PetscInt        size, s;
4372 
4373       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4374       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4375       for (s = 0; s < size; ++s) {
4376         PetscInt r = 0;
4377 
4378         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4379         if (cone[1] == v) r = 1;
4380         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4381       }
4382       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4383 #if 1
4384       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4385       for (p = 0; p < size; ++p) {
4386         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);
4387       }
4388 #endif
4389     }
4390     /* Face vertices have 2 + cells*2 supports */
4391     for (f = fStart; f < fEnd; ++f) {
4392       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4393       const PetscInt *cone, *support;
4394       PetscInt        size, s;
4395 
4396       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4397       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4398       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4399       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4400       for (s = 0; s < size; ++s) {
4401         PetscInt r = 0;
4402 
4403         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4404         if      (cone[1] == f) r = 1;
4405         else if (cone[2] == f) r = 2;
4406         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4407         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
4408       }
4409       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4410 #if 1
4411       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4412       for (p = 0; p < 2+size*2; ++p) {
4413         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);
4414       }
4415 #endif
4416     }
4417     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4418     break;
4419   case 2:
4420     /* Hex 2D */
4421     /*
4422      3---------2---------2
4423      |         |         |
4424      |    D    2    C    |
4425      |         |         |
4426      3----3----0----1----1
4427      |         |         |
4428      |    A    0    B    |
4429      |         |         |
4430      0---------0---------1
4431      */
4432     /* All cells have 4 faces */
4433     for (c = cStart; c < cEnd; ++c) {
4434       const PetscInt  newp = (c - cStart)*4;
4435       const PetscInt *cone, *ornt;
4436       PetscInt        coneNew[4], orntNew[4];
4437 
4438       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4439       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4440       /* A quad */
4441       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4442       orntNew[0] = ornt[0];
4443       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4444       orntNew[1] = 0;
4445       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4446       orntNew[2] = -2;
4447       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
4448       orntNew[3] = ornt[3];
4449       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4450       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4451 #if 1
4452       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);
4453       for (p = 0; p < 4; ++p) {
4454         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);
4455       }
4456 #endif
4457       /* B quad */
4458       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4459       orntNew[0] = ornt[0];
4460       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4461       orntNew[1] = ornt[1];
4462       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4463       orntNew[2] = 0;
4464       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
4465       orntNew[3] = -2;
4466       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4467       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4468 #if 1
4469       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);
4470       for (p = 0; p < 4; ++p) {
4471         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);
4472       }
4473 #endif
4474       /* C quad */
4475       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
4476       orntNew[0] = -2;
4477       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4478       orntNew[1] = ornt[1];
4479       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4480       orntNew[2] = ornt[2];
4481       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4482       orntNew[3] = 0;
4483       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4484       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4485 #if 1
4486       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);
4487       for (p = 0; p < 4; ++p) {
4488         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);
4489       }
4490 #endif
4491       /* D quad */
4492       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
4493       orntNew[0] = 0;
4494       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
4495       orntNew[1] = -2;
4496       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4497       orntNew[2] = ornt[2];
4498       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
4499       orntNew[3] = ornt[3];
4500       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4501       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4502 #if 1
4503       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);
4504       for (p = 0; p < 4; ++p) {
4505         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);
4506       }
4507 #endif
4508     }
4509     /* Split faces have 2 vertices and the same cells as the parent */
4510     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4511     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4512     for (f = fStart; f < fEnd; ++f) {
4513       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4514 
4515       for (r = 0; r < 2; ++r) {
4516         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4517         const PetscInt *cone, *support;
4518         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4519 
4520         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4521         coneNew[0]       = vStartNew + (cone[0] - vStart);
4522         coneNew[1]       = vStartNew + (cone[1] - vStart);
4523         coneNew[(r+1)%2] = newv;
4524         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4525 #if 1
4526         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4527         for (p = 0; p < 2; ++p) {
4528           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);
4529         }
4530 #endif
4531         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4532         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4533         for (s = 0; s < supportSize; ++s) {
4534           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4535           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4536           for (c = 0; c < coneSize; ++c) {
4537             if (cone[c] == f) break;
4538           }
4539           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
4540         }
4541         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4542 #if 1
4543         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4544         for (p = 0; p < supportSize; ++p) {
4545           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);
4546         }
4547 #endif
4548       }
4549     }
4550     /* Interior faces have 2 vertices and 2 cells */
4551     for (c = cStart; c < cEnd; ++c) {
4552       const PetscInt *cone;
4553       PetscInt        coneNew[2], supportNew[2];
4554 
4555       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4556       for (r = 0; r < 4; ++r) {
4557         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4558 
4559         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
4560         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
4561         ierr       = DMPlexSetCone(rdm, newp, coneNew);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 ((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);
4566         }
4567 #endif
4568         supportNew[0] = (c - cStart)*4 + r;
4569         supportNew[1] = (c - cStart)*4 + (r+1)%4;
4570         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4571 #if 1
4572         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4573         for (p = 0; p < 2; ++p) {
4574           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);
4575         }
4576 #endif
4577       }
4578     }
4579     /* Old vertices have identical supports */
4580     for (v = vStart; v < vEnd; ++v) {
4581       const PetscInt  newp = vStartNew + (v - vStart);
4582       const PetscInt *support, *cone;
4583       PetscInt        size, s;
4584 
4585       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4586       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4587       for (s = 0; s < size; ++s) {
4588         PetscInt r = 0;
4589 
4590         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4591         if (cone[1] == v) r = 1;
4592         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4593       }
4594       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4595 #if 1
4596       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4597       for (p = 0; p < size; ++p) {
4598         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);
4599       }
4600 #endif
4601     }
4602     /* Face vertices have 2 + cells supports */
4603     for (f = fStart; f < fEnd; ++f) {
4604       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4605       const PetscInt *cone, *support;
4606       PetscInt        size, s;
4607 
4608       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4609       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4610       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4611       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4612       for (s = 0; s < size; ++s) {
4613         PetscInt r = 0;
4614 
4615         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4616         if      (cone[1] == f) r = 1;
4617         else if (cone[2] == f) r = 2;
4618         else if (cone[3] == f) r = 3;
4619         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
4620       }
4621       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4622 #if 1
4623       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4624       for (p = 0; p < 2+size; ++p) {
4625         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);
4626       }
4627 #endif
4628     }
4629     /* Cell vertices have 4 supports */
4630     for (c = cStart; c < cEnd; ++c) {
4631       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
4632       PetscInt       supportNew[4];
4633 
4634       for (r = 0; r < 4; ++r) {
4635         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
4636       }
4637       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4638     }
4639     break;
4640   case 3:
4641     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
4642     cMax = PetscMin(cEnd, cMax);
4643     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
4644     fMax = PetscMin(fEnd, fMax);
4645     /* Interior cells have 3 faces */
4646     for (c = cStart; c < cMax; ++c) {
4647       const PetscInt  newp = cStartNew + (c - cStart)*4;
4648       const PetscInt *cone, *ornt;
4649       PetscInt        coneNew[3], orntNew[3];
4650 
4651       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4652       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4653       /* A triangle */
4654       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4655       orntNew[0] = ornt[0];
4656       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4657       orntNew[1] = -2;
4658       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
4659       orntNew[2] = ornt[2];
4660       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4661       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4662 #if 1
4663       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);
4664       for (p = 0; p < 3; ++p) {
4665         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);
4666       }
4667 #endif
4668       /* B triangle */
4669       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4670       orntNew[0] = ornt[0];
4671       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4672       orntNew[1] = ornt[1];
4673       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4674       orntNew[2] = -2;
4675       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4676       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4677 #if 1
4678       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);
4679       for (p = 0; p < 3; ++p) {
4680         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);
4681       }
4682 #endif
4683       /* C triangle */
4684       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4685       orntNew[0] = -2;
4686       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4687       orntNew[1] = ornt[1];
4688       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
4689       orntNew[2] = ornt[2];
4690       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
4691       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
4692 #if 1
4693       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);
4694       for (p = 0; p < 3; ++p) {
4695         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);
4696       }
4697 #endif
4698       /* D triangle */
4699       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
4700       orntNew[0] = 0;
4701       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
4702       orntNew[1] = 0;
4703       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
4704       orntNew[2] = 0;
4705       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
4706       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
4707 #if 1
4708       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);
4709       for (p = 0; p < 3; ++p) {
4710         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);
4711       }
4712 #endif
4713     }
4714     /*
4715      2----3----3
4716      |         |
4717      |    B    |
4718      |         |
4719      0----4--- 1
4720      |         |
4721      |    A    |
4722      |         |
4723      0----2----1
4724      */
4725     /* Hybrid cells have 4 faces */
4726     for (c = cMax; c < cEnd; ++c) {
4727       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
4728       const PetscInt *cone, *ornt;
4729       PetscInt        coneNew[4], orntNew[4];
4730 
4731       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4732       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
4733       /* A quad */
4734       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
4735       orntNew[0] = ornt[0];
4736       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
4737       orntNew[1] = ornt[1];
4738       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
4739       orntNew[2] = 0;
4740       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4741       orntNew[3] = 0;
4742       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
4743       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
4744 #if 1
4745       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);
4746       for (p = 0; p < 4; ++p) {
4747         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);
4748       }
4749 #endif
4750       /* B quad */
4751       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
4752       orntNew[0] = ornt[0];
4753       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
4754       orntNew[1] = ornt[1];
4755       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
4756       orntNew[2] = 0;
4757       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
4758       orntNew[3] = 0;
4759       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
4760       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
4761 #if 1
4762       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);
4763       for (p = 0; p < 4; ++p) {
4764         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);
4765       }
4766 #endif
4767     }
4768     /* Interior split faces have 2 vertices and the same cells as the parent */
4769     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
4770     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
4771     for (f = fStart; f < fMax; ++f) {
4772       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
4773 
4774       for (r = 0; r < 2; ++r) {
4775         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
4776         const PetscInt *cone, *support;
4777         PetscInt        coneNew[2], coneSize, c, supportSize, s;
4778 
4779         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4780         coneNew[0]       = vStartNew + (cone[0] - vStart);
4781         coneNew[1]       = vStartNew + (cone[1] - vStart);
4782         coneNew[(r+1)%2] = newv;
4783         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4784 #if 1
4785         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4786         for (p = 0; p < 2; ++p) {
4787           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);
4788         }
4789 #endif
4790         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
4791         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4792         for (s = 0; s < supportSize; ++s) {
4793           if (support[s] >= cMax) {
4794             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4795           } else {
4796             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4797             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4798             for (c = 0; c < coneSize; ++c) {
4799               if (cone[c] == f) break;
4800             }
4801             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
4802           }
4803         }
4804         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4805 #if 1
4806         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4807         for (p = 0; p < supportSize; ++p) {
4808           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);
4809         }
4810 #endif
4811       }
4812     }
4813     /* Interior cell faces have 2 vertices and 2 cells */
4814     for (c = cStart; c < cMax; ++c) {
4815       const PetscInt *cone;
4816 
4817       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4818       for (r = 0; r < 3; ++r) {
4819         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
4820         PetscInt       coneNew[2];
4821         PetscInt       supportNew[2];
4822 
4823         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
4824         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
4825         ierr       = DMPlexSetCone(rdm, newp, coneNew);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 ((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);
4830         }
4831 #endif
4832         supportNew[0] = (c - cStart)*4 + (r+1)%3;
4833         supportNew[1] = (c - cStart)*4 + 3;
4834         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4835 #if 1
4836         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4837         for (p = 0; p < 2; ++p) {
4838           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);
4839         }
4840 #endif
4841       }
4842     }
4843     /* Interior hybrid faces have 2 vertices and the same cells */
4844     for (f = fMax; f < fEnd; ++f) {
4845       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
4846       const PetscInt *cone;
4847       const PetscInt *support;
4848       PetscInt        coneNew[2];
4849       PetscInt        supportNew[2];
4850       PetscInt        size, s, r;
4851 
4852       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
4853       coneNew[0] = vStartNew + (cone[0] - vStart);
4854       coneNew[1] = vStartNew + (cone[1] - vStart);
4855       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
4856 #if 1
4857       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4858       for (p = 0; p < 2; ++p) {
4859         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);
4860       }
4861 #endif
4862       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4863       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4864       for (s = 0; s < size; ++s) {
4865         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4866         for (r = 0; r < 2; ++r) {
4867           if (cone[r+2] == f) break;
4868         }
4869         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
4870       }
4871       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4872 #if 1
4873       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4874       for (p = 0; p < size; ++p) {
4875         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);
4876       }
4877 #endif
4878     }
4879     /* Cell hybrid faces have 2 vertices and 2 cells */
4880     for (c = cMax; c < cEnd; ++c) {
4881       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
4882       const PetscInt *cone;
4883       PetscInt        coneNew[2];
4884       PetscInt        supportNew[2];
4885 
4886       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
4887       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
4888       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
4889       ierr       = DMPlexSetCone(rdm, newp, coneNew);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 ((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);
4894       }
4895 #endif
4896       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
4897       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
4898       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
4899 #if 1
4900       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
4901       for (p = 0; p < 2; ++p) {
4902         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);
4903       }
4904 #endif
4905     }
4906     /* Old vertices have identical supports */
4907     for (v = vStart; v < vEnd; ++v) {
4908       const PetscInt  newp = vStartNew + (v - vStart);
4909       const PetscInt *support, *cone;
4910       PetscInt        size, s;
4911 
4912       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
4913       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
4914       for (s = 0; s < size; ++s) {
4915         if (support[s] >= fMax) {
4916           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
4917         } else {
4918           PetscInt r = 0;
4919 
4920           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4921           if (cone[1] == v) r = 1;
4922           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
4923         }
4924       }
4925       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4926 #if 1
4927       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4928       for (p = 0; p < size; ++p) {
4929         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
4930       }
4931 #endif
4932     }
4933     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
4934     for (f = fStart; f < fMax; ++f) {
4935       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
4936       const PetscInt *cone, *support;
4937       PetscInt        size, newSize = 2, s;
4938 
4939       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
4940       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
4941       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
4942       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
4943       for (s = 0; s < size; ++s) {
4944         PetscInt r = 0;
4945 
4946         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4947         if (support[s] >= cMax) {
4948           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
4949 
4950           newSize += 1;
4951         } else {
4952           if      (cone[1] == f) r = 1;
4953           else if (cone[2] == f) r = 2;
4954           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
4955           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
4956 
4957           newSize += 2;
4958         }
4959       }
4960       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
4961 #if 1
4962       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
4963       for (p = 0; p < newSize; ++p) {
4964         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);
4965       }
4966 #endif
4967     }
4968     ierr = PetscFree(supportRef);CHKERRQ(ierr);
4969     break;
4970   default:
4971     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
4972   }
4973   PetscFunctionReturn(0);
4974 }
4975 
4976 #undef __FUNCT__
4977 #define __FUNCT__ "CellRefinerSetCoordinates"
4978 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
4979 {
4980   PetscSection   coordSection, coordSectionNew;
4981   Vec            coordinates, coordinatesNew;
4982   PetscScalar   *coords, *coordsNew;
4983   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
4984   PetscErrorCode ierr;
4985 
4986   PetscFunctionBegin;
4987   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4988   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4989   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4990   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4991   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
4992   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
4993   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
4994   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4995   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
4996   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
4997   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
4998   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
4999   if (fMax < 0) fMax = fEnd;
5000   switch (refiner) {
5001   case 1:
5002   case 2:
5003   case 3:
5004     /* Simplicial and Hex 2D */
5005     /* All vertices have the dim coordinates */
5006     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5007       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5008       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5009     }
5010     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5011     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5012     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5013     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5014     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
5015     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5016     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5017     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5018     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5019     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5020     /* Old vertices have the same coordinates */
5021     for (v = vStart; v < vEnd; ++v) {
5022       const PetscInt newv = vStartNew + (v - vStart);
5023       PetscInt       off, offnew, d;
5024 
5025       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5026       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5027       for (d = 0; d < dim; ++d) {
5028         coordsNew[offnew+d] = coords[off+d];
5029       }
5030     }
5031     /* Face vertices have the average of endpoint coordinates */
5032     for (f = fStart; f < fMax; ++f) {
5033       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5034       const PetscInt *cone;
5035       PetscInt        coneSize, offA, offB, offnew, d;
5036 
5037       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5038       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5039       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5040       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5041       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5042       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5043       for (d = 0; d < dim; ++d) {
5044         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5045       }
5046     }
5047     /* Just Hex 2D */
5048     if (refiner == 2) {
5049       /* Cell vertices have the average of corner coordinates */
5050       for (c = cStart; c < cEnd; ++c) {
5051         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5052         PetscInt      *cone = NULL;
5053         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5054 
5055         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5056         for (p = 0; p < closureSize*2; p += 2) {
5057           const PetscInt point = cone[p];
5058           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
5059         }
5060         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5061         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5062         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5063         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5064         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5065         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5066         for (d = 0; d < dim; ++d) {
5067           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5068         }
5069         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5070       }
5071     }
5072     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5073     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5074     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5075     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5076     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
5077     break;
5078   default:
5079     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5080   }
5081   PetscFunctionReturn(0);
5082 }
5083 
5084 #undef __FUNCT__
5085 #define __FUNCT__ "DMPlexCreateProcessSF"
5086 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5087 {
5088   PetscInt           numRoots, numLeaves, l;
5089   const PetscInt    *localPoints;
5090   const PetscSFNode *remotePoints;
5091   PetscInt          *localPointsNew;
5092   PetscSFNode       *remotePointsNew;
5093   PetscInt          *ranks, *ranksNew;
5094   PetscErrorCode     ierr;
5095 
5096   PetscFunctionBegin;
5097   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5098   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5099   for (l = 0; l < numLeaves; ++l) {
5100     ranks[l] = remotePoints[l].rank;
5101   }
5102   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
5103   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
5104   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5105   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5106   for (l = 0; l < numLeaves; ++l) {
5107     ranksNew[l]              = ranks[l];
5108     localPointsNew[l]        = l;
5109     remotePointsNew[l].index = 0;
5110     remotePointsNew[l].rank  = ranksNew[l];
5111   }
5112   ierr = PetscFree(ranks);CHKERRQ(ierr);
5113   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
5114   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
5115   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
5116   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5117   PetscFunctionReturn(0);
5118 }
5119 
5120 #undef __FUNCT__
5121 #define __FUNCT__ "CellRefinerCreateSF"
5122 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5123 {
5124   PetscSF            sf, sfNew, sfProcess;
5125   IS                 processRanks;
5126   MPI_Datatype       depthType;
5127   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
5128   const PetscInt    *localPoints, *neighbors;
5129   const PetscSFNode *remotePoints;
5130   PetscInt          *localPointsNew;
5131   PetscSFNode       *remotePointsNew;
5132   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
5133   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
5134   PetscErrorCode     ierr;
5135 
5136   PetscFunctionBegin;
5137   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
5138   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5139   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5140   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5141   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5142   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5143   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5144   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5145   switch (refiner) {
5146   case 3:
5147     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5148     cMax = PetscMin(cEnd, cMax);
5149     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5150     fMax = PetscMin(fEnd, fMax);
5151   }
5152   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
5153   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
5154   /* Caculate size of new SF */
5155   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5156   if (numRoots < 0) PetscFunctionReturn(0);
5157   for (l = 0; l < numLeaves; ++l) {
5158     const PetscInt p = localPoints[l];
5159 
5160     switch (refiner) {
5161     case 1:
5162       /* Simplicial 2D */
5163       if ((p >= vStart) && (p < vEnd)) {
5164         /* Old vertices stay the same */
5165         ++numLeavesNew;
5166       } else if ((p >= fStart) && (p < fEnd)) {
5167         /* Old faces add new faces and vertex */
5168         numLeavesNew += 1 + 2;
5169       } else if ((p >= cStart) && (p < cEnd)) {
5170         /* Old cells add new cells and interior faces */
5171         numLeavesNew += 4 + 3;
5172       }
5173       break;
5174     case 2:
5175       /* Hex 2D */
5176       if ((p >= vStart) && (p < vEnd)) {
5177         /* Old vertices stay the same */
5178         ++numLeavesNew;
5179       } else if ((p >= fStart) && (p < fEnd)) {
5180         /* Old faces add new faces and vertex */
5181         numLeavesNew += 1 + 2;
5182       } else if ((p >= cStart) && (p < cEnd)) {
5183         /* Old cells add new cells and interior faces */
5184         numLeavesNew += 4 + 4;
5185       }
5186       break;
5187     default:
5188       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5189     }
5190   }
5191   /* Communicate depthSizes for each remote rank */
5192   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
5193   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
5194   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
5195   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);
5196   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
5197   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
5198   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5199   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
5200   for (n = 0; n < numNeighbors; ++n) {
5201     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
5202   }
5203   depthSizeOld[depth]   = cMax;
5204   depthSizeOld[0]       = vMax;
5205   depthSizeOld[depth-1] = fMax;
5206   depthSizeOld[1]       = eMax;
5207 
5208   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5209   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
5210 
5211   depthSizeOld[depth]   = cEnd - cStart;
5212   depthSizeOld[0]       = vEnd - vStart;
5213   depthSizeOld[depth-1] = fEnd - fStart;
5214   depthSizeOld[1]       = eEnd - eStart;
5215 
5216   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5217   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
5218   for (n = 0; n < numNeighbors; ++n) {
5219     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
5220   }
5221   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
5222   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
5223   /* Calculate new point SF */
5224   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
5225   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
5226   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
5227   for (l = 0, m = 0; l < numLeaves; ++l) {
5228     PetscInt    p     = localPoints[l];
5229     PetscInt    rp    = remotePoints[l].index, n;
5230     PetscMPIInt rrank = remotePoints[l].rank;
5231 
5232     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
5233     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
5234     switch (refiner) {
5235     case 1:
5236       /* Simplicial 2D */
5237       if ((p >= vStart) && (p < vEnd)) {
5238         /* Old vertices stay the same */
5239         localPointsNew[m]        = vStartNew     + (p  - vStart);
5240         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5241         remotePointsNew[m].rank  = rrank;
5242         ++m;
5243       } else if ((p >= fStart) && (p < fEnd)) {
5244         /* Old faces add new faces and vertex */
5245         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5246         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5247         remotePointsNew[m].rank  = rrank;
5248         ++m;
5249         for (r = 0; r < 2; ++r, ++m) {
5250           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5251           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5252           remotePointsNew[m].rank  = rrank;
5253         }
5254       } else if ((p >= cStart) && (p < cEnd)) {
5255         /* Old cells add new cells and interior faces */
5256         for (r = 0; r < 4; ++r, ++m) {
5257           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5258           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5259           remotePointsNew[m].rank  = rrank;
5260         }
5261         for (r = 0; r < 3; ++r, ++m) {
5262           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
5263           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
5264           remotePointsNew[m].rank  = rrank;
5265         }
5266       }
5267       break;
5268     case 2:
5269       /* Hex 2D */
5270       if ((p >= vStart) && (p < vEnd)) {
5271         /* Old vertices stay the same */
5272         localPointsNew[m]        = vStartNew     + (p  - vStart);
5273         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5274         remotePointsNew[m].rank  = rrank;
5275         ++m;
5276       } else if ((p >= fStart) && (p < fEnd)) {
5277         /* Old faces add new faces and vertex */
5278         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5279         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5280         remotePointsNew[m].rank  = rrank;
5281         ++m;
5282         for (r = 0; r < 2; ++r, ++m) {
5283           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5284           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5285           remotePointsNew[m].rank  = rrank;
5286         }
5287       } else if ((p >= cStart) && (p < cEnd)) {
5288         /* Old cells add new cells and interior faces */
5289         for (r = 0; r < 4; ++r, ++m) {
5290           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5291           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5292           remotePointsNew[m].rank  = rrank;
5293         }
5294         for (r = 0; r < 4; ++r, ++m) {
5295           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
5296           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
5297           remotePointsNew[m].rank  = rrank;
5298         }
5299       }
5300       break;
5301     case 3:
5302       /* Hybrid simplicial 2D */
5303       if ((p >= vStart) && (p < vEnd)) {
5304         /* Old vertices stay the same */
5305         localPointsNew[m]        = vStartNew     + (p  - vStart);
5306         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
5307         remotePointsNew[m].rank  = rrank;
5308         ++m;
5309       } else if ((p >= fStart) && (p < fMax)) {
5310         /* Old interior faces add new faces and vertex */
5311         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
5312         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
5313         remotePointsNew[m].rank  = rrank;
5314         ++m;
5315         for (r = 0; r < 2; ++r, ++m) {
5316           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
5317           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
5318           remotePointsNew[m].rank  = rrank;
5319         }
5320       } else if ((p >= fMax) && (p < fEnd)) {
5321         /* Old hybrid faces stay the same */
5322         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
5323         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
5324         remotePointsNew[m].rank  = rrank;
5325         ++m;
5326       } else if ((p >= cStart) && (p < cMax)) {
5327         /* Old interior cells add new cells and interior faces */
5328         for (r = 0; r < 4; ++r, ++m) {
5329           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5330           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5331           remotePointsNew[m].rank  = rrank;
5332         }
5333         for (r = 0; r < 3; ++r, ++m) {
5334           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
5335           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
5336           remotePointsNew[m].rank  = rrank;
5337         }
5338       } else if ((p >= cStart) && (p < cMax)) {
5339         /* Old hybrid cells add new cells and hybrid face */
5340         for (r = 0; r < 2; ++r, ++m) {
5341           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
5342           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
5343           remotePointsNew[m].rank  = rrank;
5344         }
5345         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
5346         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]);
5347         remotePointsNew[m].rank  = rrank;
5348         ++m;
5349       }
5350       break;
5351     default:
5352       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5353     }
5354   }
5355   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
5356   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
5357   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
5358   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
5359   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
5360   PetscFunctionReturn(0);
5361 }
5362 
5363 #undef __FUNCT__
5364 #define __FUNCT__ "CellRefinerCreateLabels"
5365 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5366 {
5367   PetscInt       numLabels, l;
5368   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
5369   PetscErrorCode ierr;
5370 
5371   PetscFunctionBegin;
5372   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5373   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5374   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5375   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5376 
5377   cStartNew = 0;
5378   vStartNew = depthSize[2];
5379   fStartNew = depthSize[2] + depthSize[0];
5380 
5381   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
5382   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5383   switch (refiner) {
5384   case 3:
5385     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5386     cMax = PetscMin(cEnd, cMax);
5387     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5388     fMax = PetscMin(fEnd, fMax);
5389   }
5390   for (l = 0; l < numLabels; ++l) {
5391     DMLabel         label, labelNew;
5392     const char     *lname;
5393     PetscBool       isDepth;
5394     IS              valueIS;
5395     const PetscInt *values;
5396     PetscInt        numValues, val;
5397 
5398     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
5399     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
5400     if (isDepth) continue;
5401     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
5402     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
5403     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
5404     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
5405     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
5406     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
5407     for (val = 0; val < numValues; ++val) {
5408       IS              pointIS;
5409       const PetscInt *points;
5410       PetscInt        numPoints, n;
5411 
5412       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
5413       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
5414       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
5415       for (n = 0; n < numPoints; ++n) {
5416         const PetscInt p = points[n];
5417         switch (refiner) {
5418         case 1:
5419           /* Simplicial 2D */
5420           if ((p >= vStart) && (p < vEnd)) {
5421             /* Old vertices stay the same */
5422             newp = vStartNew + (p - vStart);
5423             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5424           } else if ((p >= fStart) && (p < fEnd)) {
5425             /* Old faces add new faces and vertex */
5426             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5427             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5428             for (r = 0; r < 2; ++r) {
5429               newp = fStartNew + (p - fStart)*2 + r;
5430               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5431             }
5432           } else if ((p >= cStart) && (p < cEnd)) {
5433             /* Old cells add new cells and interior faces */
5434             for (r = 0; r < 4; ++r) {
5435               newp = cStartNew + (p - cStart)*4 + r;
5436               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5437             }
5438             for (r = 0; r < 3; ++r) {
5439               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5440               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5441             }
5442           }
5443           break;
5444         case 2:
5445           /* Hex 2D */
5446           if ((p >= vStart) && (p < vEnd)) {
5447             /* Old vertices stay the same */
5448             newp = vStartNew + (p - vStart);
5449             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5450           } else if ((p >= fStart) && (p < fEnd)) {
5451             /* Old faces add new faces and vertex */
5452             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5453             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5454             for (r = 0; r < 2; ++r) {
5455               newp = fStartNew + (p - fStart)*2 + r;
5456               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5457             }
5458           } else if ((p >= cStart) && (p < cEnd)) {
5459             /* Old cells add new cells and interior faces and vertex */
5460             for (r = 0; r < 4; ++r) {
5461               newp = cStartNew + (p - cStart)*4 + r;
5462               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5463             }
5464             for (r = 0; r < 4; ++r) {
5465               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
5466               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5467             }
5468             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
5469             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5470           }
5471           break;
5472         case 3:
5473           /* Hybrid simplicial 2D */
5474           if ((p >= vStart) && (p < vEnd)) {
5475             /* Old vertices stay the same */
5476             newp = vStartNew + (p - vStart);
5477             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5478           } else if ((p >= fStart) && (p < fMax)) {
5479             /* Old interior faces add new faces and vertex */
5480             newp = vStartNew + (vEnd - vStart) + (p - fStart);
5481             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5482             for (r = 0; r < 2; ++r) {
5483               newp = fStartNew + (p - fStart)*2 + r;
5484               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5485             }
5486           } else if ((p >= fMax) && (p < fEnd)) {
5487             /* Old hybrid faces stay the same */
5488             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
5489             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5490           } else if ((p >= cStart) && (p < cMax)) {
5491             /* Old interior cells add new cells and interior faces */
5492             for (r = 0; r < 4; ++r) {
5493               newp = cStartNew + (p - cStart)*4 + r;
5494               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5495             }
5496             for (r = 0; r < 3; ++r) {
5497               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
5498               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5499             }
5500           } else if ((p >= cMax) && (p < cEnd)) {
5501             /* Old hybrid cells add new cells and hybrid face */
5502             for (r = 0; r < 2; ++r) {
5503               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
5504               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5505             }
5506             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
5507             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
5508           }
5509           break;
5510         default:
5511           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5512         }
5513       }
5514       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
5515       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
5516     }
5517     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
5518     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
5519     if (0) {
5520       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
5521       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5522       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
5523     }
5524   }
5525   PetscFunctionReturn(0);
5526 }
5527 
5528 #undef __FUNCT__
5529 #define __FUNCT__ "DMPlexRefine_Uniform"
5530 /* This will only work for interpolated meshes */
5531 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
5532 {
5533   DM             rdm;
5534   PetscInt      *depthSize;
5535   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
5536   PetscErrorCode ierr;
5537 
5538   PetscFunctionBegin;
5539   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
5540   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
5541   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5542   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
5543   /* Calculate number of new points of each depth */
5544   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5545   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
5546   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
5547   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
5548   /* Step 1: Set chart */
5549   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
5550   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
5551   /* Step 2: Set cone/support sizes */
5552   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5553   /* Step 3: Setup refined DM */
5554   ierr = DMSetUp(rdm);CHKERRQ(ierr);
5555   /* Step 4: Set cones and supports */
5556   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5557   /* Step 5: Stratify */
5558   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
5559   /* Step 6: Set coordinates for vertices */
5560   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5561   /* Step 7: Create pointSF */
5562   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5563   /* Step 8: Create labels */
5564   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
5565   ierr = PetscFree(depthSize);CHKERRQ(ierr);
5566 
5567   *dmRefined = rdm;
5568   PetscFunctionReturn(0);
5569 }
5570 
5571 #undef __FUNCT__
5572 #define __FUNCT__ "DMPlexSetRefinementUniform"
5573 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
5574 {
5575   DM_Plex *mesh = (DM_Plex*) dm->data;
5576 
5577   PetscFunctionBegin;
5578   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5579   mesh->refinementUniform = refinementUniform;
5580   PetscFunctionReturn(0);
5581 }
5582 
5583 #undef __FUNCT__
5584 #define __FUNCT__ "DMPlexGetRefinementUniform"
5585 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
5586 {
5587   DM_Plex *mesh = (DM_Plex*) dm->data;
5588 
5589   PetscFunctionBegin;
5590   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5591   PetscValidPointer(refinementUniform,  2);
5592   *refinementUniform = mesh->refinementUniform;
5593   PetscFunctionReturn(0);
5594 }
5595 
5596 #undef __FUNCT__
5597 #define __FUNCT__ "DMPlexSetRefinementLimit"
5598 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
5599 {
5600   DM_Plex *mesh = (DM_Plex*) dm->data;
5601 
5602   PetscFunctionBegin;
5603   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5604   mesh->refinementLimit = refinementLimit;
5605   PetscFunctionReturn(0);
5606 }
5607 
5608 #undef __FUNCT__
5609 #define __FUNCT__ "DMPlexGetRefinementLimit"
5610 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
5611 {
5612   DM_Plex *mesh = (DM_Plex*) dm->data;
5613 
5614   PetscFunctionBegin;
5615   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5616   PetscValidPointer(refinementLimit,  2);
5617   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
5618   *refinementLimit = mesh->refinementLimit;
5619   PetscFunctionReturn(0);
5620 }
5621 
5622 #undef __FUNCT__
5623 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
5624 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
5625 {
5626   PetscInt       dim, cStart, coneSize, cMax;
5627   PetscErrorCode ierr;
5628 
5629   PetscFunctionBegin;
5630   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5631   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
5632   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
5633   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
5634   switch (dim) {
5635   case 2:
5636     switch (coneSize) {
5637     case 3:
5638       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
5639       else *cellRefiner = 1; /* Triangular */
5640       break;
5641     case 4:
5642       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
5643       else *cellRefiner = 2; /* Quadrilateral */
5644       break;
5645     default:
5646       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
5647     }
5648     break;
5649   default:
5650     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
5651   }
5652   PetscFunctionReturn(0);
5653 }
5654 
5655 #undef __FUNCT__
5656 #define __FUNCT__ "DMRefine_Plex"
5657 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
5658 {
5659   PetscReal      refinementLimit;
5660   PetscInt       dim, cStart, cEnd;
5661   char           genname[1024], *name = NULL;
5662   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5663   PetscErrorCode ierr;
5664 
5665   PetscFunctionBegin;
5666   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
5667   if (isUniform) {
5668     CellRefiner cellRefiner;
5669 
5670     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
5671     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
5672     PetscFunctionReturn(0);
5673   }
5674   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
5675   if (refinementLimit == 0.0) PetscFunctionReturn(0);
5676   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5677   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5678   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5679   if (flg) name = genname;
5680   if (name) {
5681     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5682     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5683     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5684   }
5685   switch (dim) {
5686   case 2:
5687     if (!name || isTriangle) {
5688 #if defined(PETSC_HAVE_TRIANGLE)
5689       double  *maxVolumes;
5690       PetscInt c;
5691 
5692       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5693       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5694       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5695 #else
5696       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
5697 #endif
5698     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5699     break;
5700   case 3:
5701     if (!name || isCTetgen) {
5702 #if defined(PETSC_HAVE_CTETGEN)
5703       PetscReal *maxVolumes;
5704       PetscInt   c;
5705 
5706       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
5707       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5708       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5709 #else
5710       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5711 #endif
5712     } else if (isTetgen) {
5713 #if defined(PETSC_HAVE_TETGEN)
5714       double  *maxVolumes;
5715       PetscInt c;
5716 
5717       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
5718       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
5719       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
5720 #else
5721       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5722 #endif
5723     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5724     break;
5725   default:
5726     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
5727   }
5728   PetscFunctionReturn(0);
5729 }
5730 
5731 #undef __FUNCT__
5732 #define __FUNCT__ "DMPlexGetDepth"
5733 /*@
5734   DMPlexGetDepth - get the number of strata
5735 
5736   Not Collective
5737 
5738   Input Parameters:
5739 . dm           - The DMPlex object
5740 
5741   Output Parameters:
5742 . depth - number of strata
5743 
5744   Level: developer
5745 
5746   Notes:
5747   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
5748 
5749 .keywords: mesh, points
5750 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
5751 @*/
5752 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
5753 {
5754   PetscInt       d;
5755   PetscErrorCode ierr;
5756 
5757   PetscFunctionBegin;
5758   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5759   PetscValidPointer(depth, 2);
5760   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
5761   *depth = d-1;
5762   PetscFunctionReturn(0);
5763 }
5764 
5765 #undef __FUNCT__
5766 #define __FUNCT__ "DMPlexGetDepthStratum"
5767 /*@
5768   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
5769 
5770   Not Collective
5771 
5772   Input Parameters:
5773 + dm           - The DMPlex object
5774 - stratumValue - The requested depth
5775 
5776   Output Parameters:
5777 + start - The first point at this depth
5778 - end   - One beyond the last point at this depth
5779 
5780   Level: developer
5781 
5782 .keywords: mesh, points
5783 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
5784 @*/
5785 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5786 {
5787   DM_Plex       *mesh = (DM_Plex*) dm->data;
5788   DMLabel        next  = mesh->labels;
5789   PetscBool      flg   = PETSC_FALSE;
5790   PetscInt       depth;
5791   PetscErrorCode ierr;
5792 
5793   PetscFunctionBegin;
5794   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5795   if (stratumValue < 0) {
5796     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
5797     PetscFunctionReturn(0);
5798   } else {
5799     PetscInt pStart, pEnd;
5800 
5801     if (start) *start = 0;
5802     if (end)   *end   = 0;
5803     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5804     if (pStart == pEnd) PetscFunctionReturn(0);
5805   }
5806   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
5807   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
5808   /* We should have a generic GetLabel() and a Label class */
5809   while (next) {
5810     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
5811     if (flg) break;
5812     next = next->next;
5813   }
5814   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
5815   depth = stratumValue;
5816   if ((depth < 0) || (depth >= next->numStrata)) {
5817     if (start) *start = 0;
5818     if (end)   *end   = 0;
5819   } else {
5820     if (start) *start = next->points[next->stratumOffsets[depth]];
5821     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
5822   }
5823   PetscFunctionReturn(0);
5824 }
5825 
5826 #undef __FUNCT__
5827 #define __FUNCT__ "DMPlexGetHeightStratum"
5828 /*@
5829   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
5830 
5831   Not Collective
5832 
5833   Input Parameters:
5834 + dm           - The DMPlex object
5835 - stratumValue - The requested height
5836 
5837   Output Parameters:
5838 + start - The first point at this height
5839 - end   - One beyond the last point at this height
5840 
5841   Level: developer
5842 
5843 .keywords: mesh, points
5844 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
5845 @*/
5846 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
5847 {
5848   DM_Plex       *mesh = (DM_Plex*) dm->data;
5849   DMLabel        next  = mesh->labels;
5850   PetscBool      flg   = PETSC_FALSE;
5851   PetscInt       depth;
5852   PetscErrorCode ierr;
5853 
5854   PetscFunctionBegin;
5855   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
5856   if (stratumValue < 0) {
5857     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
5858   } else {
5859     PetscInt pStart, pEnd;
5860 
5861     if (start) *start = 0;
5862     if (end)   *end   = 0;
5863     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5864     if (pStart == pEnd) PetscFunctionReturn(0);
5865   }
5866   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
5867   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
5868   /* We should have a generic GetLabel() and a Label class */
5869   while (next) {
5870     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
5871     if (flg) break;
5872     next = next->next;
5873   }
5874   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
5875   depth = next->stratumValues[next->numStrata-1] - stratumValue;
5876   if ((depth < 0) || (depth >= next->numStrata)) {
5877     if (start) *start = 0;
5878     if (end)   *end   = 0;
5879   } else {
5880     if (start) *start = next->points[next->stratumOffsets[depth]];
5881     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
5882   }
5883   PetscFunctionReturn(0);
5884 }
5885 
5886 #undef __FUNCT__
5887 #define __FUNCT__ "DMPlexCreateSectionInitial"
5888 /* Set the number of dof on each point and separate by fields */
5889 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
5890 {
5891   PetscInt      *numDofTot;
5892   PetscInt       pStart = 0, pEnd = 0;
5893   PetscInt       p, d, f;
5894   PetscErrorCode ierr;
5895 
5896   PetscFunctionBegin;
5897   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
5898   for (d = 0; d <= dim; ++d) {
5899     numDofTot[d] = 0;
5900     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
5901   }
5902   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
5903   if (numFields > 0) {
5904     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
5905     if (numComp) {
5906       for (f = 0; f < numFields; ++f) {
5907         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
5908       }
5909     }
5910   }
5911   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
5912   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
5913   for (d = 0; d <= dim; ++d) {
5914     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
5915     for (p = pStart; p < pEnd; ++p) {
5916       for (f = 0; f < numFields; ++f) {
5917         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
5918       }
5919       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
5920     }
5921   }
5922   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
5923   PetscFunctionReturn(0);
5924 }
5925 
5926 #undef __FUNCT__
5927 #define __FUNCT__ "DMPlexCreateSectionBCDof"
5928 /* Set the number of dof on each point and separate by fields
5929    If constDof is PETSC_DETERMINE, constrain every dof on the point
5930 */
5931 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
5932 {
5933   PetscInt       numFields;
5934   PetscInt       bc;
5935   PetscErrorCode ierr;
5936 
5937   PetscFunctionBegin;
5938   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5939   for (bc = 0; bc < numBC; ++bc) {
5940     PetscInt        field = 0;
5941     const PetscInt *idx;
5942     PetscInt        n, i;
5943 
5944     if (numFields) field = bcField[bc];
5945     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
5946     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
5947     for (i = 0; i < n; ++i) {
5948       const PetscInt p        = idx[i];
5949       PetscInt       numConst = constDof;
5950 
5951       /* Constrain every dof on the point */
5952       if (numConst < 0) {
5953         if (numFields) {
5954           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
5955         } else {
5956           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
5957         }
5958       }
5959       if (numFields) {
5960         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
5961       }
5962       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
5963     }
5964     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
5965   }
5966   PetscFunctionReturn(0);
5967 }
5968 
5969 #undef __FUNCT__
5970 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
5971 /* Set the constrained indices on each point and separate by fields */
5972 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
5973 {
5974   PetscInt      *maxConstraints;
5975   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
5976   PetscErrorCode ierr;
5977 
5978   PetscFunctionBegin;
5979   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
5980   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
5981   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
5982   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
5983   for (p = pStart; p < pEnd; ++p) {
5984     PetscInt cdof;
5985 
5986     if (numFields) {
5987       for (f = 0; f < numFields; ++f) {
5988         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
5989         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
5990       }
5991     } else {
5992       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
5993       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
5994     }
5995   }
5996   for (f = 0; f < numFields; ++f) {
5997     maxConstraints[numFields] += maxConstraints[f];
5998   }
5999   if (maxConstraints[numFields]) {
6000     PetscInt *indices;
6001 
6002     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6003     for (p = pStart; p < pEnd; ++p) {
6004       PetscInt cdof, d;
6005 
6006       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6007       if (cdof) {
6008         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
6009         if (numFields) {
6010           PetscInt numConst = 0, foff = 0;
6011 
6012           for (f = 0; f < numFields; ++f) {
6013             PetscInt cfdof, fdof;
6014 
6015             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6016             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
6017             /* Change constraint numbering from absolute local dof number to field relative local dof number */
6018             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
6019             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
6020             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
6021             numConst += cfdof;
6022             foff     += fdof;
6023           }
6024           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6025         } else {
6026           for (d = 0; d < cdof; ++d) indices[d] = d;
6027         }
6028         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6029       }
6030     }
6031     ierr = PetscFree(indices);CHKERRQ(ierr);
6032   }
6033   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
6034   PetscFunctionReturn(0);
6035 }
6036 
6037 #undef __FUNCT__
6038 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
6039 /* Set the constrained field indices on each point */
6040 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
6041 {
6042   const PetscInt *points, *indices;
6043   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
6044   PetscErrorCode  ierr;
6045 
6046   PetscFunctionBegin;
6047   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6048   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
6049 
6050   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
6051   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
6052   if (!constraintIndices) {
6053     PetscInt *idx, i;
6054 
6055     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6056     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
6057     for (i = 0; i < maxDof; ++i) idx[i] = i;
6058     for (p = 0; p < numPoints; ++p) {
6059       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
6060     }
6061     ierr = PetscFree(idx);CHKERRQ(ierr);
6062   } else {
6063     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
6064     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
6065     for (p = 0; p < numPoints; ++p) {
6066       PetscInt fcdof;
6067 
6068       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
6069       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);
6070       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
6071     }
6072     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
6073   }
6074   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
6075   PetscFunctionReturn(0);
6076 }
6077 
6078 #undef __FUNCT__
6079 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
6080 /* Set the constrained indices on each point and separate by fields */
6081 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
6082 {
6083   PetscInt      *indices;
6084   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
6085   PetscErrorCode ierr;
6086 
6087   PetscFunctionBegin;
6088   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
6089   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
6090   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6091   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
6092   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6093   for (p = pStart; p < pEnd; ++p) {
6094     PetscInt cdof, d;
6095 
6096     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6097     if (cdof) {
6098       PetscInt numConst = 0, foff = 0;
6099 
6100       for (f = 0; f < numFields; ++f) {
6101         const PetscInt *fcind;
6102         PetscInt        fdof, fcdof;
6103 
6104         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
6105         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
6106         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
6107         /* Change constraint numbering from field relative local dof number to absolute local dof number */
6108         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
6109         foff     += fdof;
6110         numConst += fcdof;
6111       }
6112       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
6113       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
6114     }
6115   }
6116   ierr = PetscFree(indices);CHKERRQ(ierr);
6117   PetscFunctionReturn(0);
6118 }
6119 
6120 #undef __FUNCT__
6121 #define __FUNCT__ "DMPlexCreateSection"
6122 /*@C
6123   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
6124 
6125   Not Collective
6126 
6127   Input Parameters:
6128 + dm        - The DMPlex object
6129 . dim       - The spatial dimension of the problem
6130 . numFields - The number of fields in the problem
6131 . numComp   - An array of size numFields that holds the number of components for each field
6132 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
6133 . numBC     - The number of boundary conditions
6134 . bcField   - An array of size numBC giving the field number for each boundry condition
6135 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
6136 
6137   Output Parameter:
6138 . section - The PetscSection object
6139 
6140   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
6141   nubmer of dof for field 0 on each edge.
6142 
6143   Level: developer
6144 
6145   Fortran Notes:
6146   A Fortran 90 version is available as DMPlexCreateSectionF90()
6147 
6148 .keywords: mesh, elements
6149 .seealso: DMPlexCreate(), PetscSectionCreate()
6150 @*/
6151 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
6152 {
6153   PetscErrorCode ierr;
6154 
6155   PetscFunctionBegin;
6156   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
6157   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
6158   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
6159   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
6160   {
6161     PetscBool view = PETSC_FALSE;
6162 
6163     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
6164     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
6165   }
6166   PetscFunctionReturn(0);
6167 }
6168 
6169 #undef __FUNCT__
6170 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
6171 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
6172 {
6173   PetscSection   section;
6174   PetscErrorCode ierr;
6175 
6176   PetscFunctionBegin;
6177   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
6178   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6179   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
6180   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6181   PetscFunctionReturn(0);
6182 }
6183 
6184 #undef __FUNCT__
6185 #define __FUNCT__ "DMPlexGetCoordinateSection"
6186 /*@
6187   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
6188 
6189   Not Collective
6190 
6191   Input Parameter:
6192 . dm - The DMPlex object
6193 
6194   Output Parameter:
6195 . section - The PetscSection object
6196 
6197   Level: intermediate
6198 
6199 .keywords: mesh, coordinates
6200 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6201 @*/
6202 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
6203 {
6204   DM             cdm;
6205   PetscErrorCode ierr;
6206 
6207   PetscFunctionBegin;
6208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6209   PetscValidPointer(section, 2);
6210   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6211   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
6212   PetscFunctionReturn(0);
6213 }
6214 
6215 #undef __FUNCT__
6216 #define __FUNCT__ "DMPlexSetCoordinateSection"
6217 /*@
6218   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
6219 
6220   Not Collective
6221 
6222   Input Parameters:
6223 + dm      - The DMPlex object
6224 - section - The PetscSection object
6225 
6226   Level: intermediate
6227 
6228 .keywords: mesh, coordinates
6229 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
6230 @*/
6231 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
6232 {
6233   DM             cdm;
6234   PetscErrorCode ierr;
6235 
6236   PetscFunctionBegin;
6237   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
6238   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
6239   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
6240   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
6241   PetscFunctionReturn(0);
6242 }
6243 
6244 #undef __FUNCT__
6245 #define __FUNCT__ "DMPlexGetConeSection"
6246 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
6247 {
6248   DM_Plex *mesh = (DM_Plex*) dm->data;
6249 
6250   PetscFunctionBegin;
6251   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6252   if (section) *section = mesh->coneSection;
6253   PetscFunctionReturn(0);
6254 }
6255 
6256 #undef __FUNCT__
6257 #define __FUNCT__ "DMPlexGetCones"
6258 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
6259 {
6260   DM_Plex *mesh = (DM_Plex*) dm->data;
6261 
6262   PetscFunctionBegin;
6263   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6264   if (cones) *cones = mesh->cones;
6265   PetscFunctionReturn(0);
6266 }
6267 
6268 #undef __FUNCT__
6269 #define __FUNCT__ "DMPlexGetConeOrientations"
6270 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
6271 {
6272   DM_Plex *mesh = (DM_Plex*) dm->data;
6273 
6274   PetscFunctionBegin;
6275   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6276   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
6277   PetscFunctionReturn(0);
6278 }
6279 
6280 /******************************** FEM Support **********************************/
6281 
6282 #undef __FUNCT__
6283 #define __FUNCT__ "DMPlexVecGetClosure"
6284 /*@C
6285   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
6286 
6287   Not collective
6288 
6289   Input Parameters:
6290 + dm - The DM
6291 . section - The section describing the layout in v, or NULL to use the default section
6292 . v - The local vector
6293 - point - The sieve point in the DM
6294 
6295   Output Parameters:
6296 + csize - The number of values in the closure, or NULL
6297 - values - The array of values, which is a borrowed array and should not be freed
6298 
6299   Fortran Notes:
6300   Since it returns an array, this routine is only available in Fortran 90, and you must
6301   include petsc.h90 in your code.
6302 
6303   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6304 
6305   Level: intermediate
6306 
6307 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6308 @*/
6309 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6310 {
6311   PetscScalar   *array, *vArray;
6312   PetscInt      *points = NULL;
6313   PetscInt       offsets[32];
6314   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
6315   PetscErrorCode ierr;
6316 
6317   PetscFunctionBegin;
6318   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6319   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6320   if (!section) {
6321     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6322   }
6323   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6324   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6325   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6326   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6327   /* Compress out points not in the section */
6328   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6329   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6330     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6331       points[q*2]   = points[p];
6332       points[q*2+1] = points[p+1];
6333       ++q;
6334     }
6335   }
6336   numPoints = q;
6337   for (p = 0, size = 0; p < numPoints*2; p += 2) {
6338     PetscInt dof, fdof;
6339 
6340     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6341     for (f = 0; f < numFields; ++f) {
6342       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6343       offsets[f+1] += fdof;
6344     }
6345     size += dof;
6346   }
6347   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6348   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
6349   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
6350   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
6351   for (p = 0; p < numPoints*2; p += 2) {
6352     PetscInt     o = points[p+1];
6353     PetscInt     dof, off, d;
6354     PetscScalar *varr;
6355 
6356     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6357     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
6358     varr = &vArray[off];
6359     if (numFields) {
6360       PetscInt fdof, foff, fcomp, f, c;
6361 
6362       for (f = 0, foff = 0; f < numFields; ++f) {
6363         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6364         if (o >= 0) {
6365           for (d = 0; d < fdof; ++d, ++offsets[f]) {
6366             array[offsets[f]] = varr[foff+d];
6367           }
6368         } else {
6369           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6370           for (d = fdof/fcomp-1; d >= 0; --d) {
6371             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
6372               array[offsets[f]] = varr[foff+d*fcomp+c];
6373             }
6374           }
6375         }
6376         foff += fdof;
6377       }
6378     } else {
6379       if (o >= 0) {
6380         for (d = 0; d < dof; ++d, ++offsets[0]) {
6381           array[offsets[0]] = varr[d];
6382         }
6383       } else {
6384         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
6385           array[offsets[0]] = varr[d];
6386         }
6387       }
6388     }
6389   }
6390   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6391   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
6392   if (csize) *csize = size;
6393   *values = array;
6394   PetscFunctionReturn(0);
6395 }
6396 
6397 #undef __FUNCT__
6398 #define __FUNCT__ "DMPlexVecRestoreClosure"
6399 /*@C
6400   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
6401 
6402   Not collective
6403 
6404   Input Parameters:
6405 + dm - The DM
6406 . section - The section describing the layout in v, or NULL to use the default section
6407 . v - The local vector
6408 . point - The sieve point in the DM
6409 . csize - The number of values in the closure, or NULL
6410 - values - The array of values, which is a borrowed array and should not be freed
6411 
6412   Fortran Notes:
6413   Since it returns an array, this routine is only available in Fortran 90, and you must
6414   include petsc.h90 in your code.
6415 
6416   The csize argument is not present in the Fortran 90 binding since it is internal to the array.
6417 
6418   Level: intermediate
6419 
6420 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
6421 @*/
6422 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, PetscScalar *values[])
6423 {
6424   PetscInt       size = 0;
6425   PetscErrorCode ierr;
6426 
6427   PetscFunctionBegin;
6428   /* Should work without recalculating size */
6429   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
6430   PetscFunctionReturn(0);
6431 }
6432 
6433 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
6434 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
6435 
6436 #undef __FUNCT__
6437 #define __FUNCT__ "updatePoint_private"
6438 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6439 {
6440   PetscInt        cdof;   /* The number of constraints on this point */
6441   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6442   PetscScalar    *a;
6443   PetscInt        off, cind = 0, k;
6444   PetscErrorCode  ierr;
6445 
6446   PetscFunctionBegin;
6447   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6448   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6449   a    = &array[off];
6450   if (!cdof || setBC) {
6451     if (orientation >= 0) {
6452       for (k = 0; k < dof; ++k) {
6453         fuse(&a[k], values[k]);
6454       }
6455     } else {
6456       for (k = 0; k < dof; ++k) {
6457         fuse(&a[k], values[dof-k-1]);
6458       }
6459     }
6460   } else {
6461     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6462     if (orientation >= 0) {
6463       for (k = 0; k < dof; ++k) {
6464         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6465         fuse(&a[k], values[k]);
6466       }
6467     } else {
6468       for (k = 0; k < dof; ++k) {
6469         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
6470         fuse(&a[k], values[dof-k-1]);
6471       }
6472     }
6473   }
6474   PetscFunctionReturn(0);
6475 }
6476 
6477 #undef __FUNCT__
6478 #define __FUNCT__ "updatePointFields_private"
6479 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
6480 {
6481   PetscScalar   *a;
6482   PetscInt       numFields, off, foff, f;
6483   PetscErrorCode ierr;
6484 
6485   PetscFunctionBegin;
6486   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6487   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
6488   a    = &array[off];
6489   for (f = 0, foff = 0; f < numFields; ++f) {
6490     PetscInt        fdof, fcomp, fcdof;
6491     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6492     PetscInt        cind = 0, k, c;
6493 
6494     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6495     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6496     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
6497     if (!fcdof || setBC) {
6498       if (orientation >= 0) {
6499         for (k = 0; k < fdof; ++k) {
6500           fuse(&a[foff+k], values[foffs[f]+k]);
6501         }
6502       } else {
6503         for (k = fdof/fcomp-1; k >= 0; --k) {
6504           for (c = 0; c < fcomp; ++c) {
6505             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6506           }
6507         }
6508       }
6509     } else {
6510       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6511       if (orientation >= 0) {
6512         for (k = 0; k < fdof; ++k) {
6513           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
6514           fuse(&a[foff+k], values[foffs[f]+k]);
6515         }
6516       } else {
6517         for (k = fdof/fcomp-1; k >= 0; --k) {
6518           for (c = 0; c < fcomp; ++c) {
6519             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
6520             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
6521           }
6522         }
6523       }
6524     }
6525     foff     += fdof;
6526     foffs[f] += fdof;
6527   }
6528   PetscFunctionReturn(0);
6529 }
6530 
6531 #undef __FUNCT__
6532 #define __FUNCT__ "DMPlexVecSetClosure"
6533 /*@C
6534   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
6535 
6536   Not collective
6537 
6538   Input Parameters:
6539 + dm - The DM
6540 . section - The section describing the layout in v, or NULL to use the default sectionw
6541 . v - The local vector
6542 . point - The sieve point in the DM
6543 . values - The array of values, which is a borrowed array and should not be freed
6544 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
6545 
6546   Fortran Notes:
6547   Since it returns an array, this routine is only available in Fortran 90, and you must
6548   include petsc.h90 in your code.
6549 
6550   Level: intermediate
6551 
6552 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
6553 @*/
6554 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
6555 {
6556   PetscScalar   *array;
6557   PetscInt      *points = NULL;
6558   PetscInt       offsets[32];
6559   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
6560   PetscErrorCode ierr;
6561 
6562   PetscFunctionBegin;
6563   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6564   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
6565   if (!section) {
6566     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6567   }
6568   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6569   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6570   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6571   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6572   /* Compress out points not in the section */
6573   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6574   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6575     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6576       points[q*2]   = points[p];
6577       points[q*2+1] = points[p+1];
6578       ++q;
6579     }
6580   }
6581   numPoints = q;
6582   for (p = 0; p < numPoints*2; p += 2) {
6583     PetscInt fdof;
6584 
6585     for (f = 0; f < numFields; ++f) {
6586       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6587       offsets[f+1] += fdof;
6588     }
6589   }
6590   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6591   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
6592   if (numFields) {
6593     switch (mode) {
6594     case INSERT_VALUES:
6595       for (p = 0; p < numPoints*2; p += 2) {
6596         PetscInt o = points[p+1];
6597         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
6598       } break;
6599     case INSERT_ALL_VALUES:
6600       for (p = 0; p < numPoints*2; p += 2) {
6601         PetscInt o = points[p+1];
6602         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
6603       } break;
6604     case ADD_VALUES:
6605       for (p = 0; p < numPoints*2; p += 2) {
6606         PetscInt o = points[p+1];
6607         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
6608       } break;
6609     case ADD_ALL_VALUES:
6610       for (p = 0; p < numPoints*2; p += 2) {
6611         PetscInt o = points[p+1];
6612         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
6613       } break;
6614     default:
6615       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6616     }
6617   } else {
6618     switch (mode) {
6619     case INSERT_VALUES:
6620       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6621         PetscInt o = points[p+1];
6622         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6623         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
6624       } break;
6625     case INSERT_ALL_VALUES:
6626       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6627         PetscInt o = points[p+1];
6628         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6629         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
6630       } break;
6631     case ADD_VALUES:
6632       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6633         PetscInt o = points[p+1];
6634         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6635         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
6636       } break;
6637     case ADD_ALL_VALUES:
6638       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
6639         PetscInt o = points[p+1];
6640         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6641         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
6642       } break;
6643     default:
6644       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
6645     }
6646   }
6647   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6648   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
6649   PetscFunctionReturn(0);
6650 }
6651 
6652 #undef __FUNCT__
6653 #define __FUNCT__ "DMPlexPrintMatSetValues"
6654 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], const PetscScalar values[])
6655 {
6656   PetscMPIInt    rank;
6657   PetscInt       i, j;
6658   PetscErrorCode ierr;
6659 
6660   PetscFunctionBegin;
6661   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
6662   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
6663   for (i = 0; i < numIndices; i++) {
6664     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
6665   }
6666   for (i = 0; i < numIndices; i++) {
6667     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
6668     for (j = 0; j < numIndices; j++) {
6669 #if defined(PETSC_USE_COMPLEX)
6670       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
6671 #else
6672       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
6673 #endif
6674     }
6675     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
6676   }
6677   PetscFunctionReturn(0);
6678 }
6679 
6680 #undef __FUNCT__
6681 #define __FUNCT__ "indicesPoint_private"
6682 /* . off - The global offset of this point */
6683 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
6684 {
6685   PetscInt        dof;    /* The number of unknowns on this point */
6686   PetscInt        cdof;   /* The number of constraints on this point */
6687   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
6688   PetscInt        cind = 0, k;
6689   PetscErrorCode  ierr;
6690 
6691   PetscFunctionBegin;
6692   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
6693   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
6694   if (!cdof || setBC) {
6695     if (orientation >= 0) {
6696       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
6697     } else {
6698       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
6699     }
6700   } else {
6701     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
6702     if (orientation >= 0) {
6703       for (k = 0; k < dof; ++k) {
6704         if ((cind < cdof) && (k == cdofs[cind])) {
6705           /* Insert check for returning constrained indices */
6706           indices[*loff+k] = -(off+k+1);
6707           ++cind;
6708         } else {
6709           indices[*loff+k] = off+k-cind;
6710         }
6711       }
6712     } else {
6713       for (k = 0; k < dof; ++k) {
6714         if ((cind < cdof) && (k == cdofs[cind])) {
6715           /* Insert check for returning constrained indices */
6716           indices[*loff+dof-k-1] = -(off+k+1);
6717           ++cind;
6718         } else {
6719           indices[*loff+dof-k-1] = off+k-cind;
6720         }
6721       }
6722     }
6723   }
6724   *loff += dof;
6725   PetscFunctionReturn(0);
6726 }
6727 
6728 #undef __FUNCT__
6729 #define __FUNCT__ "indicesPointFields_private"
6730 /* . off - The global offset of this point */
6731 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
6732 {
6733   PetscInt       numFields, foff, f;
6734   PetscErrorCode ierr;
6735 
6736   PetscFunctionBegin;
6737   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6738   for (f = 0, foff = 0; f < numFields; ++f) {
6739     PetscInt        fdof, fcomp, cfdof;
6740     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
6741     PetscInt        cind = 0, k, c;
6742 
6743     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
6744     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
6745     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
6746     if (!cfdof || setBC) {
6747       if (orientation >= 0) {
6748         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
6749       } else {
6750         for (k = fdof/fcomp-1; k >= 0; --k) {
6751           for (c = 0; c < fcomp; ++c) {
6752             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
6753           }
6754         }
6755       }
6756     } else {
6757       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
6758       if (orientation >= 0) {
6759         for (k = 0; k < fdof; ++k) {
6760           if ((cind < cfdof) && (k == fcdofs[cind])) {
6761             indices[foffs[f]+k] = -(off+foff+k+1);
6762             ++cind;
6763           } else {
6764             indices[foffs[f]+k] = off+foff+k-cind;
6765           }
6766         }
6767       } else {
6768         for (k = fdof/fcomp-1; k >= 0; --k) {
6769           for (c = 0; c < fcomp; ++c) {
6770             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
6771               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
6772               ++cind;
6773             } else {
6774               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
6775             }
6776           }
6777         }
6778       }
6779     }
6780     foff     += fdof - cfdof;
6781     foffs[f] += fdof;
6782   }
6783   PetscFunctionReturn(0);
6784 }
6785 
6786 #undef __FUNCT__
6787 #define __FUNCT__ "DMPlexMatSetClosure"
6788 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, const PetscScalar values[], InsertMode mode)
6789 {
6790   DM_Plex       *mesh   = (DM_Plex*) dm->data;
6791   PetscInt      *points = NULL;
6792   PetscInt      *indices;
6793   PetscInt       offsets[32];
6794   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
6795   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
6796   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
6797   PetscErrorCode ierr;
6798 
6799   PetscFunctionBegin;
6800   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6801   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
6802   if (useDefault) {
6803     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
6804   }
6805   if (useGlobalDefault) {
6806     if (useDefault) {
6807       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
6808     } else {
6809       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6810     }
6811   }
6812   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6813   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
6814   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
6815   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6816   /* Compress out points not in the section */
6817   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6818   for (p = 0, q = 0; p < numPoints*2; p += 2) {
6819     if ((points[p] >= pStart) && (points[p] < pEnd)) {
6820       points[q*2]   = points[p];
6821       points[q*2+1] = points[p+1];
6822       ++q;
6823     }
6824   }
6825   numPoints = q;
6826   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
6827     PetscInt fdof;
6828 
6829     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
6830     for (f = 0; f < numFields; ++f) {
6831       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
6832       offsets[f+1] += fdof;
6833     }
6834     numIndices += dof;
6835   }
6836   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
6837 
6838   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
6839   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
6840   if (numFields) {
6841     for (p = 0; p < numPoints*2; p += 2) {
6842       PetscInt o = points[p+1];
6843       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
6844       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
6845     }
6846   } else {
6847     for (p = 0, off = 0; p < numPoints*2; p += 2) {
6848       PetscInt o = points[p+1];
6849       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
6850       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
6851     }
6852   }
6853   if (useGlobalDefault && !useDefault) {
6854     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6855   }
6856   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
6857   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
6858   if (ierr) {
6859     PetscMPIInt    rank;
6860     PetscErrorCode ierr2;
6861 
6862     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
6863     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
6864     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
6865     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
6866     CHKERRQ(ierr);
6867   }
6868   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
6869   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
6870   PetscFunctionReturn(0);
6871 }
6872 
6873 #undef __FUNCT__
6874 #define __FUNCT__ "DMPlexGetHybridBounds"
6875 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
6876 {
6877   DM_Plex       *mesh = (DM_Plex*) dm->data;
6878   PetscInt       dim;
6879   PetscErrorCode ierr;
6880 
6881   PetscFunctionBegin;
6882   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6883   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6884   if (cMax) *cMax = mesh->hybridPointMax[dim];
6885   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
6886   if (eMax) *eMax = mesh->hybridPointMax[1];
6887   if (vMax) *vMax = mesh->hybridPointMax[0];
6888   PetscFunctionReturn(0);
6889 }
6890 
6891 #undef __FUNCT__
6892 #define __FUNCT__ "DMPlexSetHybridBounds"
6893 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
6894 {
6895   DM_Plex       *mesh = (DM_Plex*) dm->data;
6896   PetscInt       dim;
6897   PetscErrorCode ierr;
6898 
6899   PetscFunctionBegin;
6900   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6901   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6902   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
6903   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
6904   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
6905   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
6906   PetscFunctionReturn(0);
6907 }
6908 
6909 #undef __FUNCT__
6910 #define __FUNCT__ "DMPlexGetVTKCellHeight"
6911 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
6912 {
6913   DM_Plex *mesh = (DM_Plex*) dm->data;
6914 
6915   PetscFunctionBegin;
6916   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6917   PetscValidPointer(cellHeight, 2);
6918   *cellHeight = mesh->vtkCellHeight;
6919   PetscFunctionReturn(0);
6920 }
6921 
6922 #undef __FUNCT__
6923 #define __FUNCT__ "DMPlexSetVTKCellHeight"
6924 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
6925 {
6926   DM_Plex *mesh = (DM_Plex*) dm->data;
6927 
6928   PetscFunctionBegin;
6929   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6930   mesh->vtkCellHeight = cellHeight;
6931   PetscFunctionReturn(0);
6932 }
6933 
6934 #undef __FUNCT__
6935 #define __FUNCT__ "DMPlexCreateNumbering_Private"
6936 /* We can easily have a form that takes an IS instead */
6937 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
6938 {
6939   PetscSection   section, globalSection;
6940   PetscInt      *numbers, p;
6941   PetscErrorCode ierr;
6942 
6943   PetscFunctionBegin;
6944   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
6945   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
6946   for (p = pStart; p < pEnd; ++p) {
6947     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
6948   }
6949   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
6950   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
6951   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
6952   for (p = pStart; p < pEnd; ++p) {
6953     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
6954   }
6955   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
6956   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
6957   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
6958   PetscFunctionReturn(0);
6959 }
6960 
6961 #undef __FUNCT__
6962 #define __FUNCT__ "DMPlexGetCellNumbering"
6963 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
6964 {
6965   DM_Plex       *mesh = (DM_Plex*) dm->data;
6966   PetscInt       cellHeight, cStart, cEnd, cMax;
6967   PetscErrorCode ierr;
6968 
6969   PetscFunctionBegin;
6970   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6971   if (!mesh->globalCellNumbers) {
6972     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
6973     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
6974     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
6975     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
6976     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
6977   }
6978   *globalCellNumbers = mesh->globalCellNumbers;
6979   PetscFunctionReturn(0);
6980 }
6981 
6982 #undef __FUNCT__
6983 #define __FUNCT__ "DMPlexGetVertexNumbering"
6984 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
6985 {
6986   DM_Plex       *mesh = (DM_Plex*) dm->data;
6987   PetscInt       vStart, vEnd, vMax;
6988   PetscErrorCode ierr;
6989 
6990   PetscFunctionBegin;
6991   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6992   if (!mesh->globalVertexNumbers) {
6993     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6994     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
6995     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
6996     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
6997   }
6998   *globalVertexNumbers = mesh->globalVertexNumbers;
6999   PetscFunctionReturn(0);
7000 }
7001 
7002 
7003 #undef __FUNCT__
7004 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
7005 /*@C
7006   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
7007   the local section and an SF describing the section point overlap.
7008 
7009   Input Parameters:
7010   + s - The PetscSection for the local field layout
7011   . sf - The SF describing parallel layout of the section points
7012   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
7013   . label - The label specifying the points
7014   - labelValue - The label stratum specifying the points
7015 
7016   Output Parameter:
7017   . gsection - The PetscSection for the global field layout
7018 
7019   Note: This gives negative sizes and offsets to points not owned by this process
7020 
7021   Level: developer
7022 
7023 .seealso: PetscSectionCreate()
7024 @*/
7025 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
7026 {
7027   PetscInt      *neg;
7028   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
7029   PetscErrorCode ierr;
7030 
7031   PetscFunctionBegin;
7032   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
7033   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
7034   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
7035   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
7036   /* Mark ghost points with negative dof */
7037   for (p = pStart; p < pEnd; ++p) {
7038     PetscInt value;
7039 
7040     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
7041     if (value != labelValue) continue;
7042     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
7043     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
7044     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
7045     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
7046     neg[p-pStart] = -(dof+1);
7047   }
7048   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
7049   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
7050   if (nroots >= 0) {
7051     if (nroots > pEnd - pStart) {
7052       PetscInt *tmpDof;
7053       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7054       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
7055       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7056       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
7057       for (p = pStart; p < pEnd; ++p) {
7058         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
7059       }
7060       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
7061     } else {
7062       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7063       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
7064     }
7065   }
7066   /* Calculate new sizes, get proccess offset, and calculate point offsets */
7067   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7068     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
7069 
7070     (*gsection)->atlasOff[p] = off;
7071 
7072     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
7073   }
7074   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
7075   globalOff -= off;
7076   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
7077     (*gsection)->atlasOff[p] += globalOff;
7078 
7079     neg[p] = -((*gsection)->atlasOff[p]+1);
7080   }
7081   /* Put in negative offsets for ghost points */
7082   if (nroots >= 0) {
7083     if (nroots > pEnd - pStart) {
7084       PetscInt *tmpOff;
7085       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
7086       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
7087       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7088       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
7089       for (p = pStart; p < pEnd; ++p) {
7090         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
7091       }
7092       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
7093     } else {
7094       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7095       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
7096     }
7097   }
7098   ierr = PetscFree(neg);CHKERRQ(ierr);
7099   PetscFunctionReturn(0);
7100 }
7101