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