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