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