xref: /petsc/src/dm/impls/plex/plex.c (revision 06bbee04bcaf8bdf4f7dd7eae3598a1fed0691a4)
1 #include <petsc-private/dmpleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 #include <petsc-private/vecimpl.h>
4 #include <petsc-private/isimpl.h>
5 
6 /* Logging support */
7 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
8 
9 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
10 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     PetscMPIInt size;
282 
283     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
284     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
285     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
286     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
287     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
288     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
289     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
290     if (depth == 1) {
291       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
292       pEnd = pEnd - pStart;
293       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
294       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
295       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
296       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
297       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
298       pEnd = pEnd - pStart;
299       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
300       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
301       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
302       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
303     } else {
304       for (d = 0; d <= dim; d++) {
305         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
306         pEnd = pEnd - pStart;
307         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
308         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
309         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
310         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
311       }
312     }
313     ierr = PetscFree(sizes);CHKERRQ(ierr);
314   }
315   PetscFunctionReturn(0);
316 }
317 
318 #undef __FUNCT__
319 #define __FUNCT__ "DMView_Plex"
320 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
321 {
322   PetscBool      iascii, isbinary;
323   PetscErrorCode ierr;
324 
325   PetscFunctionBegin;
326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
327   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
329   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
330   if (iascii) {
331     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
332 #if 0
333   } else if (isbinary) {
334     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
335 #endif
336   }
337   PetscFunctionReturn(0);
338 }
339 
340 #undef __FUNCT__
341 #define __FUNCT__ "DMDestroy_Plex"
342 PetscErrorCode DMDestroy_Plex(DM dm)
343 {
344   DM_Plex       *mesh = (DM_Plex*) dm->data;
345   DMLabel        next  = mesh->labels;
346   PetscErrorCode ierr;
347 
348   PetscFunctionBegin;
349   if (--mesh->refct > 0) PetscFunctionReturn(0);
350   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
353   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
355   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
356   while (next) {
357     DMLabel tmp = next->next;
358 
359     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
360     next = tmp;
361   }
362   ierr = DMLabelDestroy(&mesh->subpointMap);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
364   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
365   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
366   ierr = PetscFree(mesh);CHKERRQ(ierr);
367   PetscFunctionReturn(0);
368 }
369 
370 #undef __FUNCT__
371 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
372 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
373 {
374   const PetscInt *support = NULL;
375   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
376   PetscErrorCode  ierr;
377 
378   PetscFunctionBegin;
379   if (useClosure) {
380     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
381     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
382     for (s = 0; s < supportSize; ++s) {
383       const PetscInt *cone = NULL;
384       PetscInt        coneSize, c, q;
385 
386       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
387       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
388       for (c = 0; c < coneSize; ++c) {
389         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
390           if (cone[c] == adj[q]) break;
391         }
392         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
393       }
394     }
395   } else {
396     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
397     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
398     for (s = 0; s < supportSize; ++s) {
399       const PetscInt *cone = NULL;
400       PetscInt        coneSize, c, q;
401 
402       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
403       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
404       for (c = 0; c < coneSize; ++c) {
405         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
406           if (cone[c] == adj[q]) break;
407         }
408         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
409       }
410     }
411   }
412   *adjSize = numAdj;
413   PetscFunctionReturn(0);
414 }
415 
416 #undef __FUNCT__
417 #define __FUNCT__ "DMPlexGetAdjacency_Private"
418 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
419 {
420   const PetscInt *star  = tmpClosure;
421   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
422   PetscErrorCode  ierr;
423 
424   PetscFunctionBegin;
425   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
426   for (s = 2; s < starSize*2; s += 2) {
427     const PetscInt *closure = NULL;
428     PetscInt        closureSize, c, q;
429 
430     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
431     for (c = 0; c < closureSize*2; c += 2) {
432       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
433         if (closure[c] == adj[q]) break;
434       }
435       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
436     }
437     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
438   }
439   *adjSize = numAdj;
440   PetscFunctionReturn(0);
441 }
442 
443 #undef __FUNCT__
444 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
445 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
446 {
447   DM_Plex *mesh = (DM_Plex*) dm->data;
448 
449   PetscFunctionBegin;
450   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
451   mesh->preallocCenterDim = preallocCenterDim;
452   PetscFunctionReturn(0);
453 }
454 
455 #undef __FUNCT__
456 #define __FUNCT__ "DMPlexPreallocateOperator"
457 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
458 {
459   DM_Plex           *mesh = (DM_Plex*) dm->data;
460   MPI_Comm           comm;
461   PetscSF            sf, sfDof, sfAdj;
462   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
463   PetscInt           nleaves, l, p;
464   const PetscInt    *leaves;
465   const PetscSFNode *remotes;
466   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
467   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
468   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
469   PetscLayout        rLayout;
470   PetscInt           locRows, rStart, rEnd, r;
471   PetscMPIInt        size;
472   PetscBool          useClosure, debug = PETSC_FALSE;
473   PetscErrorCode     ierr;
474 
475   PetscFunctionBegin;
476   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
477   ierr = PetscOptionsGetBool(NULL, "-dm_view_preallocation", &debug, NULL);CHKERRQ(ierr);
478   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
479   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
480   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
481   /* Create dof SF based on point SF */
482   if (debug) {
483     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
487     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
488     ierr = PetscSFView(sf, NULL);CHKERRQ(ierr);
489   }
490   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
491   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
492   if (debug) {
493     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
494     ierr = PetscSFView(sfDof, NULL);CHKERRQ(ierr);
495   }
496   /* Create section for dof adjacency (dof ==> # adj dof) */
497   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
498   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
499   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
500   if (mesh->preallocCenterDim == dim) {
501     useClosure = PETSC_FALSE;
502   } else if (mesh->preallocCenterDim == 0) {
503     useClosure = PETSC_TRUE;
504   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
505 
506   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
507   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
510   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
511   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
512   /*   Fill in the ghost dofs on the interface */
513   ierr = PetscSFGetGraph(sf, NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
514   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
515   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
516 
517   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
518   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
519 
520   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
521 
522   /*
523    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
524     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
525        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
526     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
527        Create sfAdj connecting rootSectionAdj and leafSectionAdj
528     3. Visit unowned points on interface, write adjacencies to adj
529        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
530     4. Visit owned points on interface, write adjacencies to rootAdj
531        Remove redundancy in rootAdj
532    ** The last two traversals use transitive closure
533     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
534        Allocate memory addressed by sectionAdj (cols)
535     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
536    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
537   */
538 
539   for (l = 0; l < nleaves; ++l) {
540     PetscInt dof, off, d, q;
541     PetscInt p = leaves[l], numAdj = maxAdjSize;
542 
543     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
544     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
545     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
546     for (q = 0; q < numAdj; ++q) {
547       PetscInt ndof, ncdof;
548 
549       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
550       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
551       for (d = off; d < off+dof; ++d) {
552         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
553       }
554     }
555   }
556   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
557   if (debug) {
558     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
559     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
560   }
561   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
562   if (size > 1) {
563     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
564     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
565   }
566   if (debug) {
567     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
568     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
569   }
570   /* Add in local adjacency sizes for owned dofs on interface (roots) */
571   for (p = pStart; p < pEnd; ++p) {
572     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
573 
574     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
575     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
576     if (!dof) continue;
577     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
578     if (adof <= 0) continue;
579     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
580     for (q = 0; q < numAdj; ++q) {
581       PetscInt ndof, ncdof;
582 
583       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
584       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
585       for (d = off; d < off+dof; ++d) {
586         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
587       }
588     }
589   }
590   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
591   if (debug) {
592     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
593     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
594   }
595   /* Create adj SF based on dof SF */
596   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
597   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
598   if (debug) {
599     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
600     ierr = PetscSFView(sfAdj, NULL);CHKERRQ(ierr);
601   }
602   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
603   /* Create leaf adjacency */
604   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
605   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
606   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
607   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
608   for (l = 0; l < nleaves; ++l) {
609     PetscInt dof, off, d, q;
610     PetscInt p = leaves[l], numAdj = maxAdjSize;
611 
612     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
613     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
614     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
615     for (d = off; d < off+dof; ++d) {
616       PetscInt aoff, i = 0;
617 
618       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
619       for (q = 0; q < numAdj; ++q) {
620         PetscInt ndof, ncdof, ngoff, nd;
621 
622         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
623         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
624         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
625         for (nd = 0; nd < ndof-ncdof; ++nd) {
626           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
627           ++i;
628         }
629       }
630     }
631   }
632   /* Debugging */
633   if (debug) {
634     IS tmp;
635     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
636     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
637     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
638   }
639   /* Gather adjacenct indices to root */
640   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
641   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
642   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
643   if (size > 1) {
644     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
645     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
646   }
647   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
648   ierr = PetscFree(adj);CHKERRQ(ierr);
649   /* Debugging */
650   if (debug) {
651     IS tmp;
652     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
653     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
654     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
655   }
656   /* Add in local adjacency indices for owned dofs on interface (roots) */
657   for (p = pStart; p < pEnd; ++p) {
658     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
659 
660     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
661     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
662     if (!dof) continue;
663     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
664     if (adof <= 0) continue;
665     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
666     for (d = off; d < off+dof; ++d) {
667       PetscInt adof, aoff, i;
668 
669       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
670       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
671       i    = adof-1;
672       for (q = 0; q < numAdj; ++q) {
673         PetscInt ndof, ncdof, ngoff, nd;
674 
675         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
676         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
677         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
678         for (nd = 0; nd < ndof-ncdof; ++nd) {
679           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
680           --i;
681         }
682       }
683     }
684   }
685   /* Debugging */
686   if (debug) {
687     IS tmp;
688     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
689     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
690     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
691   }
692   /* Compress indices */
693   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
694   for (p = pStart; p < pEnd; ++p) {
695     PetscInt dof, cdof, off, d;
696     PetscInt adof, aoff;
697 
698     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
699     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
700     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
701     if (!dof) continue;
702     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
703     if (adof <= 0) continue;
704     for (d = off; d < off+dof-cdof; ++d) {
705       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
706       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
707       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
708       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
709     }
710   }
711   /* Debugging */
712   if (debug) {
713     IS tmp;
714     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
715     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
716     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
717     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
718     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
719   }
720   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
721   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
722   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
723   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
724   for (p = pStart; p < pEnd; ++p) {
725     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
726     PetscBool found  = PETSC_TRUE;
727 
728     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
729     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
730     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
731     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
732     for (d = 0; d < dof-cdof; ++d) {
733       PetscInt ldof, rdof;
734 
735       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
736       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
737       if (ldof > 0) {
738         /* We do not own this point */
739       } else if (rdof > 0) {
740         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
741       } else {
742         found = PETSC_FALSE;
743       }
744     }
745     if (found) continue;
746     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
747     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
748     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
749     for (q = 0; q < numAdj; ++q) {
750       PetscInt ndof, ncdof, noff;
751 
752       /* Adjacent points may not be in the section chart */
753       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
754       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
755       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
756       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
757       for (d = goff; d < goff+dof-cdof; ++d) {
758         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
759       }
760     }
761   }
762   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
763   if (debug) {
764     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
765     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
766   }
767   /* Get adjacent indices */
768   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
769   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
770   for (p = pStart; p < pEnd; ++p) {
771     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
772     PetscBool found  = PETSC_TRUE;
773 
774     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
775     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
776     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
777     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
778     for (d = 0; d < dof-cdof; ++d) {
779       PetscInt ldof, rdof;
780 
781       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
782       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
783       if (ldof > 0) {
784         /* We do not own this point */
785       } else if (rdof > 0) {
786         PetscInt aoff, roff;
787 
788         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
789         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
790         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
791       } else {
792         found = PETSC_FALSE;
793       }
794     }
795     if (found) continue;
796     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
797     for (d = goff; d < goff+dof-cdof; ++d) {
798       PetscInt adof, aoff, i = 0;
799 
800       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
801       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
802       for (q = 0; q < numAdj; ++q) {
803         PetscInt        ndof, ncdof, ngoff, nd;
804         const PetscInt *ncind;
805 
806         /* Adjacent points may not be in the section chart */
807         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
808         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
809         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
810         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
811         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
812         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
813           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
814         }
815       }
816       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
817     }
818   }
819   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
820   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
821   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
822   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
823   /* Debugging */
824   if (debug) {
825     IS tmp;
826     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
827     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
828     ierr = ISView(tmp, NULL);CHKERRQ(ierr);
829   }
830   /* Create allocation vectors from adjacency graph */
831   ierr = MatGetLocalSize(A, &locRows, NULL);CHKERRQ(ierr);
832   ierr = PetscLayoutCreate(PetscObjectComm((PetscObject)A), &rLayout);CHKERRQ(ierr);
833   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
834   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
835   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
836   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
837   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
838   /* Only loop over blocks of rows */
839   if (rStart%bs || rEnd%bs) SETERRQ3(PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
840   for (r = rStart/bs; r < rEnd/bs; ++r) {
841     const PetscInt row = r*bs;
842     PetscInt       numCols, cStart, c;
843 
844     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
845     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
846     for (c = cStart; c < cStart+numCols; ++c) {
847       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
848         ++dnz[r-rStart];
849         if (cols[c] >= row) ++dnzu[r-rStart];
850       } else {
851         ++onz[r-rStart];
852         if (cols[c] >= row) ++onzu[r-rStart];
853       }
854     }
855   }
856   if (bs > 1) {
857     for (r = 0; r < locRows/bs; ++r) {
858       dnz[r]  /= bs;
859       onz[r]  /= bs;
860       dnzu[r] /= bs;
861       onzu[r] /= bs;
862     }
863   }
864   /* Set matrix pattern */
865   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
866   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
867   /* Fill matrix with zeros */
868   if (fillMatrix) {
869     PetscScalar *values;
870     PetscInt     maxRowLen = 0;
871 
872     for (r = rStart; r < rEnd; ++r) {
873       PetscInt len;
874 
875       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
876       maxRowLen = PetscMax(maxRowLen, len);
877     }
878     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
879     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
880     for (r = rStart; r < rEnd; ++r) {
881       PetscInt numCols, cStart;
882 
883       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
884       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
885       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
886     }
887     ierr = PetscFree(values);CHKERRQ(ierr);
888     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
889     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
890   }
891   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
892   ierr = PetscFree(cols);CHKERRQ(ierr);
893   PetscFunctionReturn(0);
894 }
895 
896 #if 0
897 #undef __FUNCT__
898 #define __FUNCT__ "DMPlexPreallocateOperator_2"
899 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
900 {
901   PetscInt       *tmpClosure,*tmpAdj,*visits;
902   PetscInt        c,cStart,cEnd,pStart,pEnd;
903   PetscErrorCode  ierr;
904 
905   PetscFunctionBegin;
906   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
907   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
908   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
909 
910   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
911 
912   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
913   npoints = pEnd - pStart;
914 
915   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
916   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
917   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
918   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
919   for (c=cStart; c<cEnd; c++) {
920     PetscInt *support = tmpClosure;
921     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
922     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
923   }
924   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
925   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
926   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
927   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
928 
929   ierr = PetscSFGetRanks();CHKERRQ(ierr);
930 
931 
932   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
933   for (c=cStart; c<cEnd; c++) {
934     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
935     /*
936      Depth-first walk of transitive closure.
937      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
938      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
939      */
940   }
941 
942   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
943   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
944   PetscFunctionReturn(0);
945 }
946 #endif
947 
948 #undef __FUNCT__
949 #define __FUNCT__ "DMCreateMatrix_Plex"
950 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
951 {
952   PetscSection   section, sectionGlobal;
953   PetscInt       bs = -1;
954   PetscInt       localSize;
955   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
956   PetscErrorCode ierr;
957 
958   PetscFunctionBegin;
959 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
960   ierr = MatInitializePackage(NULL);CHKERRQ(ierr);
961 #endif
962   if (!mtype) mtype = MATAIJ;
963   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
964   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
965   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
966   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
967   ierr = MatCreate(PetscObjectComm((PetscObject)dm), J);CHKERRQ(ierr);
968   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
969   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
970   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
975   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
976   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
977   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
978   /* Check for symmetric storage */
979   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
980   if (isSymmetric) {
981     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
982   }
983   if (!isShell) {
984     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
985     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
986 
987     if (bs < 0) {
988       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
989         PetscInt pStart, pEnd, p, dof, cdof;
990 
991         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
992         for (p = pStart; p < pEnd; ++p) {
993           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
994           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
995           if (dof-cdof) {
996             if (bs < 0) {
997               bs = dof-cdof;
998             } else if (bs != dof-cdof) {
999               /* Layout does not admit a pointwise block size */
1000               bs = 1;
1001               break;
1002             }
1003           }
1004         }
1005         /* Must have same blocksize on all procs (some might have no points) */
1006         bsLocal = bs;
1007         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1008         bsLocal = bs < 0 ? bsMax : bs;
1009         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
1010         if (bsMin != bsMax) {
1011           bs = 1;
1012         } else {
1013           bs = bsMax;
1014         }
1015       } else {
1016         bs = 1;
1017       }
1018     }
1019     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1020     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1021     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1022     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1023     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1024     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1025     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1026   }
1027   PetscFunctionReturn(0);
1028 }
1029 
1030 #undef __FUNCT__
1031 #define __FUNCT__ "DMPlexGetDimension"
1032 /*@
1033   DMPlexGetDimension - Return the topological mesh dimension
1034 
1035   Not collective
1036 
1037   Input Parameter:
1038 . mesh - The DMPlex
1039 
1040   Output Parameter:
1041 . dim - The topological mesh dimension
1042 
1043   Level: beginner
1044 
1045 .seealso: DMPlexCreate()
1046 @*/
1047 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1048 {
1049   DM_Plex *mesh = (DM_Plex*) dm->data;
1050 
1051   PetscFunctionBegin;
1052   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1053   PetscValidPointer(dim, 2);
1054   *dim = mesh->dim;
1055   PetscFunctionReturn(0);
1056 }
1057 
1058 #undef __FUNCT__
1059 #define __FUNCT__ "DMPlexSetDimension"
1060 /*@
1061   DMPlexSetDimension - Set the topological mesh dimension
1062 
1063   Collective on mesh
1064 
1065   Input Parameters:
1066 + mesh - The DMPlex
1067 - dim - The topological mesh dimension
1068 
1069   Level: beginner
1070 
1071 .seealso: DMPlexCreate()
1072 @*/
1073 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1074 {
1075   DM_Plex *mesh = (DM_Plex*) dm->data;
1076 
1077   PetscFunctionBegin;
1078   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1079   PetscValidLogicalCollectiveInt(dm, dim, 2);
1080   mesh->dim               = dim;
1081   mesh->preallocCenterDim = dim;
1082   PetscFunctionReturn(0);
1083 }
1084 
1085 #undef __FUNCT__
1086 #define __FUNCT__ "DMPlexGetChart"
1087 /*@
1088   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1089 
1090   Not collective
1091 
1092   Input Parameter:
1093 . mesh - The DMPlex
1094 
1095   Output Parameters:
1096 + pStart - The first mesh point
1097 - pEnd   - The upper bound for mesh points
1098 
1099   Level: beginner
1100 
1101 .seealso: DMPlexCreate(), DMPlexSetChart()
1102 @*/
1103 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1104 {
1105   DM_Plex       *mesh = (DM_Plex*) dm->data;
1106   PetscErrorCode ierr;
1107 
1108   PetscFunctionBegin;
1109   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1110   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1111   PetscFunctionReturn(0);
1112 }
1113 
1114 #undef __FUNCT__
1115 #define __FUNCT__ "DMPlexSetChart"
1116 /*@
1117   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1118 
1119   Not collective
1120 
1121   Input Parameters:
1122 + mesh - The DMPlex
1123 . pStart - The first mesh point
1124 - pEnd   - The upper bound for mesh points
1125 
1126   Output Parameters:
1127 
1128   Level: beginner
1129 
1130 .seealso: DMPlexCreate(), DMPlexGetChart()
1131 @*/
1132 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1133 {
1134   DM_Plex       *mesh = (DM_Plex*) dm->data;
1135   PetscErrorCode ierr;
1136 
1137   PetscFunctionBegin;
1138   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1139   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1140   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1141   PetscFunctionReturn(0);
1142 }
1143 
1144 #undef __FUNCT__
1145 #define __FUNCT__ "DMPlexGetConeSize"
1146 /*@
1147   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1148 
1149   Not collective
1150 
1151   Input Parameters:
1152 + mesh - The DMPlex
1153 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1154 
1155   Output Parameter:
1156 . size - The cone size for point p
1157 
1158   Level: beginner
1159 
1160 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1161 @*/
1162 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1163 {
1164   DM_Plex       *mesh = (DM_Plex*) dm->data;
1165   PetscErrorCode ierr;
1166 
1167   PetscFunctionBegin;
1168   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1169   PetscValidPointer(size, 3);
1170   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1171   PetscFunctionReturn(0);
1172 }
1173 
1174 #undef __FUNCT__
1175 #define __FUNCT__ "DMPlexSetConeSize"
1176 /*@
1177   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1178 
1179   Not collective
1180 
1181   Input Parameters:
1182 + mesh - The DMPlex
1183 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1184 - size - The cone size for point p
1185 
1186   Output Parameter:
1187 
1188   Note:
1189   This should be called after DMPlexSetChart().
1190 
1191   Level: beginner
1192 
1193 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1194 @*/
1195 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1196 {
1197   DM_Plex       *mesh = (DM_Plex*) dm->data;
1198   PetscErrorCode ierr;
1199 
1200   PetscFunctionBegin;
1201   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1202   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1203 
1204   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1205   PetscFunctionReturn(0);
1206 }
1207 
1208 #undef __FUNCT__
1209 #define __FUNCT__ "DMPlexGetCone"
1210 /*@C
1211   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1212 
1213   Not collective
1214 
1215   Input Parameters:
1216 + mesh - The DMPlex
1217 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1218 
1219   Output Parameter:
1220 . cone - An array of points which are on the in-edges for point p
1221 
1222   Level: beginner
1223 
1224   Note:
1225   This routine is not available in Fortran.
1226 
1227 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1228 @*/
1229 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1230 {
1231   DM_Plex       *mesh = (DM_Plex*) dm->data;
1232   PetscInt       off;
1233   PetscErrorCode ierr;
1234 
1235   PetscFunctionBegin;
1236   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1237   PetscValidPointer(cone, 3);
1238   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1239   *cone = &mesh->cones[off];
1240   PetscFunctionReturn(0);
1241 }
1242 
1243 #undef __FUNCT__
1244 #define __FUNCT__ "DMPlexSetCone"
1245 /*@
1246   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1247 
1248   Not collective
1249 
1250   Input Parameters:
1251 + mesh - The DMPlex
1252 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1253 - cone - An array of points which are on the in-edges for point p
1254 
1255   Output Parameter:
1256 
1257   Note:
1258   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1259 
1260   Level: beginner
1261 
1262 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1263 @*/
1264 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1265 {
1266   DM_Plex       *mesh = (DM_Plex*) dm->data;
1267   PetscInt       pStart, pEnd;
1268   PetscInt       dof, off, c;
1269   PetscErrorCode ierr;
1270 
1271   PetscFunctionBegin;
1272   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1273   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1274   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1275   if (dof) PetscValidPointer(cone, 3);
1276   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1277   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);
1278   for (c = 0; c < dof; ++c) {
1279     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);
1280     mesh->cones[off+c] = cone[c];
1281   }
1282   PetscFunctionReturn(0);
1283 }
1284 
1285 #undef __FUNCT__
1286 #define __FUNCT__ "DMPlexGetConeOrientation"
1287 /*@C
1288   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1289 
1290   Not collective
1291 
1292   Input Parameters:
1293 + mesh - The DMPlex
1294 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1295 
1296   Output Parameter:
1297 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1298                     integer giving the prescription for cone traversal. If it is negative, the cone is
1299                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1300                     the index of the cone point on which to start.
1301 
1302   Level: beginner
1303 
1304   Note:
1305   This routine is not available in Fortran.
1306 
1307 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1308 @*/
1309 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1310 {
1311   DM_Plex       *mesh = (DM_Plex*) dm->data;
1312   PetscInt       off;
1313   PetscErrorCode ierr;
1314 
1315   PetscFunctionBegin;
1316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1317 #if defined(PETSC_USE_DEBUG)
1318   {
1319     PetscInt dof;
1320     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1321     if (dof) PetscValidPointer(coneOrientation, 3);
1322   }
1323 #endif
1324   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1325 
1326   *coneOrientation = &mesh->coneOrientations[off];
1327   PetscFunctionReturn(0);
1328 }
1329 
1330 #undef __FUNCT__
1331 #define __FUNCT__ "DMPlexSetConeOrientation"
1332 /*@
1333   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1334 
1335   Not collective
1336 
1337   Input Parameters:
1338 + mesh - The DMPlex
1339 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1340 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1341                     integer giving the prescription for cone traversal. If it is negative, the cone is
1342                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1343                     the index of the cone point on which to start.
1344 
1345   Output Parameter:
1346 
1347   Note:
1348   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1349 
1350   Level: beginner
1351 
1352 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1353 @*/
1354 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1355 {
1356   DM_Plex       *mesh = (DM_Plex*) dm->data;
1357   PetscInt       pStart, pEnd;
1358   PetscInt       dof, off, c;
1359   PetscErrorCode ierr;
1360 
1361   PetscFunctionBegin;
1362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1363   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1364   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1365   if (dof) PetscValidPointer(coneOrientation, 3);
1366   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1367   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);
1368   for (c = 0; c < dof; ++c) {
1369     PetscInt cdof, o = coneOrientation[c];
1370 
1371     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1372     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);
1373     mesh->coneOrientations[off+c] = o;
1374   }
1375   PetscFunctionReturn(0);
1376 }
1377 
1378 #undef __FUNCT__
1379 #define __FUNCT__ "DMPlexInsertCone"
1380 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1381 {
1382   DM_Plex       *mesh = (DM_Plex*) dm->data;
1383   PetscInt       pStart, pEnd;
1384   PetscInt       dof, off;
1385   PetscErrorCode ierr;
1386 
1387   PetscFunctionBegin;
1388   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1389   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1390   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1391   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1392   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);
1393   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);
1394   if (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);
1395   mesh->cones[off+conePos] = conePoint;
1396   PetscFunctionReturn(0);
1397 }
1398 
1399 #undef __FUNCT__
1400 #define __FUNCT__ "DMPlexGetSupportSize"
1401 /*@
1402   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1403 
1404   Not collective
1405 
1406   Input Parameters:
1407 + mesh - The DMPlex
1408 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1409 
1410   Output Parameter:
1411 . size - The support size for point p
1412 
1413   Level: beginner
1414 
1415 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1416 @*/
1417 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1418 {
1419   DM_Plex       *mesh = (DM_Plex*) dm->data;
1420   PetscErrorCode ierr;
1421 
1422   PetscFunctionBegin;
1423   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1424   PetscValidPointer(size, 3);
1425   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1426   PetscFunctionReturn(0);
1427 }
1428 
1429 #undef __FUNCT__
1430 #define __FUNCT__ "DMPlexSetSupportSize"
1431 /*@
1432   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1433 
1434   Not collective
1435 
1436   Input Parameters:
1437 + mesh - The DMPlex
1438 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1439 - size - The support size for point p
1440 
1441   Output Parameter:
1442 
1443   Note:
1444   This should be called after DMPlexSetChart().
1445 
1446   Level: beginner
1447 
1448 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1449 @*/
1450 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1451 {
1452   DM_Plex       *mesh = (DM_Plex*) dm->data;
1453   PetscErrorCode ierr;
1454 
1455   PetscFunctionBegin;
1456   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1457   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1458 
1459   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1460   PetscFunctionReturn(0);
1461 }
1462 
1463 #undef __FUNCT__
1464 #define __FUNCT__ "DMPlexGetSupport"
1465 /*@C
1466   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1467 
1468   Not collective
1469 
1470   Input Parameters:
1471 + mesh - The DMPlex
1472 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1473 
1474   Output Parameter:
1475 . support - An array of points which are on the out-edges for point p
1476 
1477   Level: beginner
1478 
1479 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1480 @*/
1481 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1482 {
1483   DM_Plex       *mesh = (DM_Plex*) dm->data;
1484   PetscInt       off;
1485   PetscErrorCode ierr;
1486 
1487   PetscFunctionBegin;
1488   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1489   PetscValidPointer(support, 3);
1490   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1491   *support = &mesh->supports[off];
1492   PetscFunctionReturn(0);
1493 }
1494 
1495 #undef __FUNCT__
1496 #define __FUNCT__ "DMPlexSetSupport"
1497 /*@
1498   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1499 
1500   Not collective
1501 
1502   Input Parameters:
1503 + mesh - The DMPlex
1504 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1505 - support - An array of points which are on the in-edges for point p
1506 
1507   Output Parameter:
1508 
1509   Note:
1510   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1511 
1512   Level: beginner
1513 
1514 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1515 @*/
1516 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1517 {
1518   DM_Plex       *mesh = (DM_Plex*) dm->data;
1519   PetscInt       pStart, pEnd;
1520   PetscInt       dof, off, c;
1521   PetscErrorCode ierr;
1522 
1523   PetscFunctionBegin;
1524   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1525   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1526   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1527   if (dof) PetscValidPointer(support, 3);
1528   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1529   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);
1530   for (c = 0; c < dof; ++c) {
1531     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);
1532     mesh->supports[off+c] = support[c];
1533   }
1534   PetscFunctionReturn(0);
1535 }
1536 
1537 #undef __FUNCT__
1538 #define __FUNCT__ "DMPlexInsertSupport"
1539 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1540 {
1541   DM_Plex       *mesh = (DM_Plex*) dm->data;
1542   PetscInt       pStart, pEnd;
1543   PetscInt       dof, off;
1544   PetscErrorCode ierr;
1545 
1546   PetscFunctionBegin;
1547   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1548   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1549   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1550   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1551   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);
1552   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);
1553   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);
1554   mesh->supports[off+supportPos] = supportPoint;
1555   PetscFunctionReturn(0);
1556 }
1557 
1558 #undef __FUNCT__
1559 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1560 /*@C
1561   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1562 
1563   Not collective
1564 
1565   Input Parameters:
1566 + mesh - The DMPlex
1567 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1568 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1569 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1570 
1571   Output Parameters:
1572 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1573 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1574 
1575   Note:
1576   If using internal storage (points is NULL on input), each call overwrites the last output.
1577 
1578   Level: beginner
1579 
1580 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1581 @*/
1582 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1583 {
1584   DM_Plex        *mesh = (DM_Plex*) dm->data;
1585   PetscInt       *closure, *fifo;
1586   const PetscInt *tmp = NULL, *tmpO = NULL;
1587   PetscInt        tmpSize, t;
1588   PetscInt        depth       = 0, maxSize;
1589   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1590   PetscErrorCode  ierr;
1591 
1592   PetscFunctionBegin;
1593   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1594   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1595   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1596   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1597   if (*points) {
1598     closure = *points;
1599   } else {
1600     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1601   }
1602   closure[0] = p; closure[1] = 0;
1603   /* This is only 1-level */
1604   if (useCone) {
1605     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1606     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1607     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1608   } else {
1609     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1610     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1611   }
1612   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1613     const PetscInt cp = tmp[t];
1614     const PetscInt co = tmpO ? tmpO[t] : 0;
1615 
1616     closure[closureSize]   = cp;
1617     closure[closureSize+1] = co;
1618     fifo[fifoSize]         = cp;
1619     fifo[fifoSize+1]       = co;
1620   }
1621   while (fifoSize - fifoStart) {
1622     const PetscInt q   = fifo[fifoStart];
1623     const PetscInt o   = fifo[fifoStart+1];
1624     const PetscInt rev = o >= 0 ? 0 : 1;
1625     const PetscInt off = rev ? -(o+1) : o;
1626 
1627     if (useCone) {
1628       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1629       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1630       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1631     } else {
1632       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1633       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1634       tmpO = NULL;
1635     }
1636     for (t = 0; t < tmpSize; ++t) {
1637       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1638       const PetscInt cp = tmp[i];
1639       /* Must propogate orientation */
1640       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1641       PetscInt       c;
1642 
1643       /* Check for duplicate */
1644       for (c = 0; c < closureSize; c += 2) {
1645         if (closure[c] == cp) break;
1646       }
1647       if (c == closureSize) {
1648         closure[closureSize]   = cp;
1649         closure[closureSize+1] = co;
1650         fifo[fifoSize]         = cp;
1651         fifo[fifoSize+1]       = co;
1652         closureSize           += 2;
1653         fifoSize              += 2;
1654       }
1655     }
1656     fifoStart += 2;
1657   }
1658   if (numPoints) *numPoints = closureSize/2;
1659   if (points)    *points    = closure;
1660   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1661   PetscFunctionReturn(0);
1662 }
1663 
1664 #undef __FUNCT__
1665 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1666 /*@C
1667   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1668 
1669   Not collective
1670 
1671   Input Parameters:
1672 + mesh - The DMPlex
1673 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1674 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1675 - points - If points is NULL on input, internal storage will be returned, otherwise the provided array is used
1676 
1677   Output Parameters:
1678 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1679 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1680 
1681   Note:
1682   If not using internal storage (points is not NULL on input), this call is unnecessary
1683 
1684   Level: beginner
1685 
1686 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1687 @*/
1688 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1689 {
1690   PetscErrorCode ierr;
1691 
1692   PetscFunctionBegin;
1693   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1694   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1695   PetscFunctionReturn(0);
1696 }
1697 
1698 #undef __FUNCT__
1699 #define __FUNCT__ "DMPlexGetFaces"
1700 /*
1701   DMPlexGetFaces -
1702 
1703   Note: This will only work for cell-vertex meshes.
1704 */
1705 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1706 {
1707   DM_Plex        *mesh = (DM_Plex*) dm->data;
1708   const PetscInt *cone = NULL;
1709   PetscInt        depth = 0, dim, coneSize;
1710   PetscErrorCode  ierr;
1711 
1712   PetscFunctionBegin;
1713   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1714   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1715   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1716   if (depth > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1717   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1718   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1719   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1720   switch (dim) {
1721   case 2:
1722     switch (coneSize) {
1723     case 3:
1724       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1725       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1726       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1727       *numFaces         = 3;
1728       *faceSize         = 2;
1729       *faces            = mesh->facesTmp;
1730       break;
1731     case 4:
1732       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1733       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1734       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1735       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1736       *numFaces         = 4;
1737       *faceSize         = 2;
1738       *faces            = mesh->facesTmp;
1739       break;
1740     default:
1741       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1742     }
1743     break;
1744   case 3:
1745     switch (coneSize) {
1746     case 3:
1747       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1748       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1749       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1750       *numFaces         = 3;
1751       *faceSize         = 2;
1752       *faces            = mesh->facesTmp;
1753       break;
1754     case 4:
1755       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1756       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1757       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1758       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1759       *numFaces         = 4;
1760       *faceSize         = 3;
1761       *faces            = mesh->facesTmp;
1762       break;
1763     default:
1764       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1765     }
1766     break;
1767   default:
1768     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1769   }
1770   PetscFunctionReturn(0);
1771 }
1772 
1773 #undef __FUNCT__
1774 #define __FUNCT__ "DMPlexGetMaxSizes"
1775 /*@
1776   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1777 
1778   Not collective
1779 
1780   Input Parameter:
1781 . mesh - The DMPlex
1782 
1783   Output Parameters:
1784 + maxConeSize - The maximum number of in-edges
1785 - maxSupportSize - The maximum number of out-edges
1786 
1787   Level: beginner
1788 
1789 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1790 @*/
1791 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1792 {
1793   DM_Plex *mesh = (DM_Plex*) dm->data;
1794 
1795   PetscFunctionBegin;
1796   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1797   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1798   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1799   PetscFunctionReturn(0);
1800 }
1801 
1802 #undef __FUNCT__
1803 #define __FUNCT__ "DMSetUp_Plex"
1804 PetscErrorCode DMSetUp_Plex(DM dm)
1805 {
1806   DM_Plex       *mesh = (DM_Plex*) dm->data;
1807   PetscInt       size;
1808   PetscErrorCode ierr;
1809 
1810   PetscFunctionBegin;
1811   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1812   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1813   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1814   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1815   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1816   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1817   if (mesh->maxSupportSize) {
1818     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1819     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1820     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1821   }
1822   PetscFunctionReturn(0);
1823 }
1824 
1825 #undef __FUNCT__
1826 #define __FUNCT__ "DMCreateSubDM_Plex"
1827 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1828 {
1829   PetscSection   section, sectionGlobal;
1830   PetscInt      *subIndices;
1831   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1832   PetscErrorCode ierr;
1833 
1834   PetscFunctionBegin;
1835   if (!numFields) PetscFunctionReturn(0);
1836   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1837   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1838   if (!section) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1839   if (!sectionGlobal) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1840   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1841   if (numFields > nF) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1842   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1843   for (p = pStart; p < pEnd; ++p) {
1844     PetscInt gdof;
1845 
1846     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1847     if (gdof > 0) {
1848       for (f = 0; f < numFields; ++f) {
1849         PetscInt fdof, fcdof;
1850 
1851         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1852         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1853         subSize += fdof-fcdof;
1854       }
1855     }
1856   }
1857   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1858   for (p = pStart; p < pEnd; ++p) {
1859     PetscInt gdof, goff;
1860 
1861     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1862     if (gdof > 0) {
1863       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1864       for (f = 0; f < numFields; ++f) {
1865         PetscInt fdof, fcdof, fc, f2, poff = 0;
1866 
1867         /* Can get rid of this loop by storing field information in the global section */
1868         for (f2 = 0; f2 < fields[f]; ++f2) {
1869           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1870           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1871           poff += fdof-fcdof;
1872         }
1873         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1874         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1875         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1876           subIndices[subOff] = goff+poff+fc;
1877         }
1878       }
1879     }
1880   }
1881   if (is) {ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1882   if (subdm) {
1883     PetscSection subsection;
1884     PetscBool    haveNull = PETSC_FALSE;
1885     PetscInt     f, nf = 0;
1886 
1887     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1888     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1889     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1890     ierr = PetscSectionDestroy(&subsection);CHKERRQ(ierr);
1891     for (f = 0; f < numFields; ++f) {
1892       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1893       if ((*subdm)->nullspaceConstructors[f]) {
1894         haveNull = PETSC_TRUE;
1895         nf       = f;
1896       }
1897     }
1898     if (haveNull) {
1899       MatNullSpace nullSpace;
1900 
1901       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1902       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1903       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1904     }
1905     if (dm->fields) {
1906       if (nF != dm->numFields) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1907       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1908       for (f = 0; f < numFields; ++f) {
1909         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1910       }
1911       if (numFields == 1) {
1912         MatNullSpace space;
1913         Mat          pmat;
1914 
1915         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1916         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1917         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1918         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1919         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1920         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1921       }
1922     }
1923   }
1924   PetscFunctionReturn(0);
1925 }
1926 
1927 #undef __FUNCT__
1928 #define __FUNCT__ "DMPlexSymmetrize"
1929 /*@
1930   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1931 
1932   Not collective
1933 
1934   Input Parameter:
1935 . mesh - The DMPlex
1936 
1937   Output Parameter:
1938 
1939   Note:
1940   This should be called after all calls to DMPlexSetCone()
1941 
1942   Level: beginner
1943 
1944 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1945 @*/
1946 PetscErrorCode DMPlexSymmetrize(DM dm)
1947 {
1948   DM_Plex       *mesh = (DM_Plex*) dm->data;
1949   PetscInt      *offsets;
1950   PetscInt       supportSize;
1951   PetscInt       pStart, pEnd, p;
1952   PetscErrorCode ierr;
1953 
1954   PetscFunctionBegin;
1955   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1956   if (mesh->supports) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1957   /* Calculate support sizes */
1958   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1959   for (p = pStart; p < pEnd; ++p) {
1960     PetscInt dof, off, c;
1961 
1962     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1963     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1964     for (c = off; c < off+dof; ++c) {
1965       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1966     }
1967   }
1968   for (p = pStart; p < pEnd; ++p) {
1969     PetscInt dof;
1970 
1971     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1972 
1973     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1974   }
1975   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1976   /* Calculate supports */
1977   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1978   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1979   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1980   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1981   for (p = pStart; p < pEnd; ++p) {
1982     PetscInt dof, off, c;
1983 
1984     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1985     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1986     for (c = off; c < off+dof; ++c) {
1987       const PetscInt q = mesh->cones[c];
1988       PetscInt       offS;
1989 
1990       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1991 
1992       mesh->supports[offS+offsets[q]] = p;
1993       ++offsets[q];
1994     }
1995   }
1996   ierr = PetscFree(offsets);CHKERRQ(ierr);
1997   PetscFunctionReturn(0);
1998 }
1999 
2000 #undef __FUNCT__
2001 #define __FUNCT__ "DMPlexSetDepth_Private"
2002 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
2003 {
2004   PetscInt       d;
2005   PetscErrorCode ierr;
2006 
2007   PetscFunctionBegin;
2008   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2009   if (d < 0) {
2010     /* We are guaranteed that the point has a cone since the depth was not yet set */
2011     const PetscInt *cone = NULL;
2012     PetscInt        dCone;
2013 
2014     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2015     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2016     d    = dCone+1;
2017     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2018   }
2019   *depth = d;
2020   PetscFunctionReturn(0);
2021 }
2022 
2023 #undef __FUNCT__
2024 #define __FUNCT__ "DMPlexStratify"
2025 /*@
2026   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2027   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2028   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2029   the DAG.
2030 
2031   Not collective
2032 
2033   Input Parameter:
2034 . mesh - The DMPlex
2035 
2036   Output Parameter:
2037 
2038   Notes:
2039   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2040   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2041 
2042   This should be called after all calls to DMPlexSymmetrize()
2043 
2044   Level: beginner
2045 
2046 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2047 @*/
2048 PetscErrorCode DMPlexStratify(DM dm)
2049 {
2050   DM_Plex       *mesh = (DM_Plex*) dm->data;
2051   PetscInt       pStart, pEnd, p;
2052   PetscInt       numRoots = 0, numLeaves = 0;
2053   PetscErrorCode ierr;
2054 
2055   PetscFunctionBegin;
2056   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2057   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2058   /* Calculate depth */
2059   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2060   /* Initialize roots and count leaves */
2061   for (p = pStart; p < pEnd; ++p) {
2062     PetscInt coneSize, supportSize;
2063 
2064     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2065     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2066     if (!coneSize && supportSize) {
2067       ++numRoots;
2068       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2069     } else if (!supportSize && coneSize) {
2070       ++numLeaves;
2071     } else if (!supportSize && !coneSize) {
2072       /* Isolated points */
2073       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2074     }
2075   }
2076   if (numRoots + numLeaves == (pEnd - pStart)) {
2077     for (p = pStart; p < pEnd; ++p) {
2078       PetscInt coneSize, supportSize;
2079 
2080       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2081       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2082       if (!supportSize && coneSize) {
2083         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2084       }
2085     }
2086   } else {
2087     /* This might be slow since lookup is not fast */
2088     for (p = pStart; p < pEnd; ++p) {
2089       PetscInt depth;
2090 
2091       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2092     }
2093   }
2094   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2095   PetscFunctionReturn(0);
2096 }
2097 
2098 #undef __FUNCT__
2099 #define __FUNCT__ "DMPlexGetJoin"
2100 /*@C
2101   DMPlexGetJoin - Get an array for the join of the set of points
2102 
2103   Not Collective
2104 
2105   Input Parameters:
2106 + dm - The DMPlex object
2107 . numPoints - The number of input points for the join
2108 - points - The input points
2109 
2110   Output Parameters:
2111 + numCoveredPoints - The number of points in the join
2112 - coveredPoints - The points in the join
2113 
2114   Level: intermediate
2115 
2116   Note: Currently, this is restricted to a single level join
2117 
2118 .keywords: mesh
2119 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2120 @*/
2121 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2122 {
2123   DM_Plex       *mesh = (DM_Plex*) dm->data;
2124   PetscInt      *join[2];
2125   PetscInt       joinSize, i = 0;
2126   PetscInt       dof, off, p, c, m;
2127   PetscErrorCode ierr;
2128 
2129   PetscFunctionBegin;
2130   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2131   PetscValidPointer(points, 2);
2132   PetscValidPointer(numCoveredPoints, 3);
2133   PetscValidPointer(coveredPoints, 4);
2134   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2135   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2136   /* Copy in support of first point */
2137   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2138   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2139   for (joinSize = 0; joinSize < dof; ++joinSize) {
2140     join[i][joinSize] = mesh->supports[off+joinSize];
2141   }
2142   /* Check each successive support */
2143   for (p = 1; p < numPoints; ++p) {
2144     PetscInt newJoinSize = 0;
2145 
2146     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2147     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2148     for (c = 0; c < dof; ++c) {
2149       const PetscInt point = mesh->supports[off+c];
2150 
2151       for (m = 0; m < joinSize; ++m) {
2152         if (point == join[i][m]) {
2153           join[1-i][newJoinSize++] = point;
2154           break;
2155         }
2156       }
2157     }
2158     joinSize = newJoinSize;
2159     i        = 1-i;
2160   }
2161   *numCoveredPoints = joinSize;
2162   *coveredPoints    = join[i];
2163   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2164   PetscFunctionReturn(0);
2165 }
2166 
2167 #undef __FUNCT__
2168 #define __FUNCT__ "DMPlexRestoreJoin"
2169 /*@C
2170   DMPlexRestoreJoin - Restore an array for the join of the set of points
2171 
2172   Not Collective
2173 
2174   Input Parameters:
2175 + dm - The DMPlex object
2176 . numPoints - The number of input points for the join
2177 - points - The input points
2178 
2179   Output Parameters:
2180 + numCoveredPoints - The number of points in the join
2181 - coveredPoints - The points in the join
2182 
2183   Level: intermediate
2184 
2185 .keywords: mesh
2186 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2187 @*/
2188 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2189 {
2190   PetscErrorCode ierr;
2191 
2192   PetscFunctionBegin;
2193   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2194   PetscValidPointer(coveredPoints, 4);
2195   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2196   PetscFunctionReturn(0);
2197 }
2198 
2199 #undef __FUNCT__
2200 #define __FUNCT__ "DMPlexGetFullJoin"
2201 /*@C
2202   DMPlexGetFullJoin - Get an array for the join of the set of points
2203 
2204   Not Collective
2205 
2206   Input Parameters:
2207 + dm - The DMPlex object
2208 . numPoints - The number of input points for the join
2209 - points - The input points
2210 
2211   Output Parameters:
2212 + numCoveredPoints - The number of points in the join
2213 - coveredPoints - The points in the join
2214 
2215   Level: intermediate
2216 
2217 .keywords: mesh
2218 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2219 @*/
2220 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2221 {
2222   DM_Plex       *mesh = (DM_Plex*) dm->data;
2223   PetscInt      *offsets, **closures;
2224   PetscInt      *join[2];
2225   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2226   PetscInt       p, d, c, m;
2227   PetscErrorCode ierr;
2228 
2229   PetscFunctionBegin;
2230   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2231   PetscValidPointer(points, 2);
2232   PetscValidPointer(numCoveredPoints, 3);
2233   PetscValidPointer(coveredPoints, 4);
2234 
2235   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2236   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2237   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2238   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2239   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2240   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2241   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2242 
2243   for (p = 0; p < numPoints; ++p) {
2244     PetscInt closureSize;
2245 
2246     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2247 
2248     offsets[p*(depth+2)+0] = 0;
2249     for (d = 0; d < depth+1; ++d) {
2250       PetscInt pStart, pEnd, i;
2251 
2252       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2253       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2254         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2255           offsets[p*(depth+2)+d+1] = i;
2256           break;
2257         }
2258       }
2259       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2260     }
2261     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);
2262   }
2263   for (d = 0; d < depth+1; ++d) {
2264     PetscInt dof;
2265 
2266     /* Copy in support of first point */
2267     dof = offsets[d+1] - offsets[d];
2268     for (joinSize = 0; joinSize < dof; ++joinSize) {
2269       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2270     }
2271     /* Check each successive cone */
2272     for (p = 1; p < numPoints && joinSize; ++p) {
2273       PetscInt newJoinSize = 0;
2274 
2275       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2276       for (c = 0; c < dof; ++c) {
2277         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2278 
2279         for (m = 0; m < joinSize; ++m) {
2280           if (point == join[i][m]) {
2281             join[1-i][newJoinSize++] = point;
2282             break;
2283           }
2284         }
2285       }
2286       joinSize = newJoinSize;
2287       i        = 1-i;
2288     }
2289     if (joinSize) break;
2290   }
2291   *numCoveredPoints = joinSize;
2292   *coveredPoints    = join[i];
2293   for (p = 0; p < numPoints; ++p) {
2294     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, NULL, &closures[p]);CHKERRQ(ierr);
2295   }
2296   ierr = PetscFree(closures);CHKERRQ(ierr);
2297   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2298   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2299   PetscFunctionReturn(0);
2300 }
2301 
2302 #undef __FUNCT__
2303 #define __FUNCT__ "DMPlexGetMeet"
2304 /*@C
2305   DMPlexGetMeet - Get an array for the meet of the set of points
2306 
2307   Not Collective
2308 
2309   Input Parameters:
2310 + dm - The DMPlex object
2311 . numPoints - The number of input points for the meet
2312 - points - The input points
2313 
2314   Output Parameters:
2315 + numCoveredPoints - The number of points in the meet
2316 - coveredPoints - The points in the meet
2317 
2318   Level: intermediate
2319 
2320   Note: Currently, this is restricted to a single level meet
2321 
2322 .keywords: mesh
2323 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2324 @*/
2325 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2326 {
2327   DM_Plex       *mesh = (DM_Plex*) dm->data;
2328   PetscInt      *meet[2];
2329   PetscInt       meetSize, i = 0;
2330   PetscInt       dof, off, p, c, m;
2331   PetscErrorCode ierr;
2332 
2333   PetscFunctionBegin;
2334   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2335   PetscValidPointer(points, 2);
2336   PetscValidPointer(numCoveringPoints, 3);
2337   PetscValidPointer(coveringPoints, 4);
2338   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2339   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2340   /* Copy in cone of first point */
2341   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2342   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2343   for (meetSize = 0; meetSize < dof; ++meetSize) {
2344     meet[i][meetSize] = mesh->cones[off+meetSize];
2345   }
2346   /* Check each successive cone */
2347   for (p = 1; p < numPoints; ++p) {
2348     PetscInt newMeetSize = 0;
2349 
2350     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2351     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2352     for (c = 0; c < dof; ++c) {
2353       const PetscInt point = mesh->cones[off+c];
2354 
2355       for (m = 0; m < meetSize; ++m) {
2356         if (point == meet[i][m]) {
2357           meet[1-i][newMeetSize++] = point;
2358           break;
2359         }
2360       }
2361     }
2362     meetSize = newMeetSize;
2363     i        = 1-i;
2364   }
2365   *numCoveringPoints = meetSize;
2366   *coveringPoints    = meet[i];
2367   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2368   PetscFunctionReturn(0);
2369 }
2370 
2371 #undef __FUNCT__
2372 #define __FUNCT__ "DMPlexRestoreMeet"
2373 /*@C
2374   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2375 
2376   Not Collective
2377 
2378   Input Parameters:
2379 + dm - The DMPlex object
2380 . numPoints - The number of input points for the meet
2381 - points - The input points
2382 
2383   Output Parameters:
2384 + numCoveredPoints - The number of points in the meet
2385 - coveredPoints - The points in the meet
2386 
2387   Level: intermediate
2388 
2389 .keywords: mesh
2390 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2391 @*/
2392 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2393 {
2394   PetscErrorCode ierr;
2395 
2396   PetscFunctionBegin;
2397   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2398   PetscValidPointer(coveredPoints, 4);
2399   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2400   PetscFunctionReturn(0);
2401 }
2402 
2403 #undef __FUNCT__
2404 #define __FUNCT__ "DMPlexGetFullMeet"
2405 /*@C
2406   DMPlexGetFullMeet - Get an array for the meet of the set of points
2407 
2408   Not Collective
2409 
2410   Input Parameters:
2411 + dm - The DMPlex object
2412 . numPoints - The number of input points for the meet
2413 - points - The input points
2414 
2415   Output Parameters:
2416 + numCoveredPoints - The number of points in the meet
2417 - coveredPoints - The points in the meet
2418 
2419   Level: intermediate
2420 
2421 .keywords: mesh
2422 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2423 @*/
2424 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2425 {
2426   DM_Plex       *mesh = (DM_Plex*) dm->data;
2427   PetscInt      *offsets, **closures;
2428   PetscInt      *meet[2];
2429   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2430   PetscInt       p, h, c, m;
2431   PetscErrorCode ierr;
2432 
2433   PetscFunctionBegin;
2434   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2435   PetscValidPointer(points, 2);
2436   PetscValidPointer(numCoveredPoints, 3);
2437   PetscValidPointer(coveredPoints, 4);
2438 
2439   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2440   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2441   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2442   maxSize = PetscPowInt(mesh->maxConeSize,height);
2443   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2444   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2445 
2446   for (p = 0; p < numPoints; ++p) {
2447     PetscInt closureSize;
2448 
2449     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2450 
2451     offsets[p*(height+2)+0] = 0;
2452     for (h = 0; h < height+1; ++h) {
2453       PetscInt pStart, pEnd, i;
2454 
2455       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2456       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2457         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2458           offsets[p*(height+2)+h+1] = i;
2459           break;
2460         }
2461       }
2462       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2463     }
2464     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);
2465   }
2466   for (h = 0; h < height+1; ++h) {
2467     PetscInt dof;
2468 
2469     /* Copy in cone of first point */
2470     dof = offsets[h+1] - offsets[h];
2471     for (meetSize = 0; meetSize < dof; ++meetSize) {
2472       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2473     }
2474     /* Check each successive cone */
2475     for (p = 1; p < numPoints && meetSize; ++p) {
2476       PetscInt newMeetSize = 0;
2477 
2478       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2479       for (c = 0; c < dof; ++c) {
2480         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2481 
2482         for (m = 0; m < meetSize; ++m) {
2483           if (point == meet[i][m]) {
2484             meet[1-i][newMeetSize++] = point;
2485             break;
2486           }
2487         }
2488       }
2489       meetSize = newMeetSize;
2490       i        = 1-i;
2491     }
2492     if (meetSize) break;
2493   }
2494   *numCoveredPoints = meetSize;
2495   *coveredPoints    = meet[i];
2496   for (p = 0; p < numPoints; ++p) {
2497     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, NULL, &closures[p]);CHKERRQ(ierr);
2498   }
2499   ierr = PetscFree(closures);CHKERRQ(ierr);
2500   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2501   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2502   PetscFunctionReturn(0);
2503 }
2504 
2505 #undef __FUNCT__
2506 #define __FUNCT__ "DMPlexGetNumFaceVertices_Internal"
2507 PetscErrorCode DMPlexGetNumFaceVertices_Internal(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2508 {
2509   MPI_Comm       comm;
2510   PetscInt       cellDim;
2511   PetscErrorCode ierr;
2512 
2513   PetscFunctionBegin;
2514   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2515   PetscValidPointer(numFaceVertices,3);
2516   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2517   switch (cellDim) {
2518   case 0:
2519     *numFaceVertices = 0;
2520     break;
2521   case 1:
2522     *numFaceVertices = 1;
2523     break;
2524   case 2:
2525     switch (numCorners) {
2526     case 3: /* triangle */
2527       *numFaceVertices = 2; /* Edge has 2 vertices */
2528       break;
2529     case 4: /* quadrilateral */
2530       *numFaceVertices = 2; /* Edge has 2 vertices */
2531       break;
2532     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2533       *numFaceVertices = 3; /* Edge has 3 vertices */
2534       break;
2535     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2536       *numFaceVertices = 3; /* Edge has 3 vertices */
2537       break;
2538     default:
2539       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2540     }
2541     break;
2542   case 3:
2543     switch (numCorners) {
2544     case 4: /* tetradehdron */
2545       *numFaceVertices = 3; /* Face has 3 vertices */
2546       break;
2547     case 6: /* tet cohesive cells */
2548       *numFaceVertices = 4; /* Face has 4 vertices */
2549       break;
2550     case 8: /* hexahedron */
2551       *numFaceVertices = 4; /* Face has 4 vertices */
2552       break;
2553     case 9: /* tet cohesive Lagrange cells */
2554       *numFaceVertices = 6; /* Face has 6 vertices */
2555       break;
2556     case 10: /* quadratic tetrahedron */
2557       *numFaceVertices = 6; /* Face has 6 vertices */
2558       break;
2559     case 12: /* hex cohesive Lagrange cells */
2560       *numFaceVertices = 6; /* Face has 6 vertices */
2561       break;
2562     case 18: /* quadratic tet cohesive Lagrange cells */
2563       *numFaceVertices = 6; /* Face has 6 vertices */
2564       break;
2565     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2566       *numFaceVertices = 9; /* Face has 9 vertices */
2567       break;
2568     default:
2569       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2570     }
2571     break;
2572   default:
2573     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2574   }
2575   PetscFunctionReturn(0);
2576 }
2577 
2578 #undef __FUNCT__
2579 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2580 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2581 {
2582   const PetscInt maxFaceCases = 30;
2583   PetscInt       numFaceCases = 0;
2584   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2585   PetscInt      *off, *adj;
2586   PetscInt      *neighborCells, *tmpClosure;
2587   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2588   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2589   PetscErrorCode ierr;
2590 
2591   PetscFunctionBegin;
2592   /* For parallel partitioning, I think you have to communicate supports */
2593   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2594   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2595   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2596   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2597   if (cEnd - cStart == 0) {
2598     if (numVertices) *numVertices = 0;
2599     if (offsets)   *offsets   = NULL;
2600     if (adjacency) *adjacency = NULL;
2601     PetscFunctionReturn(0);
2602   }
2603   numCells = cEnd - cStart;
2604   /* Setup face recognition */
2605   if (depth == 1) {
2606     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 */
2607 
2608     for (c = cStart; c < cEnd; ++c) {
2609       PetscInt corners;
2610 
2611       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2612       if (!cornersSeen[corners]) {
2613         PetscInt nFV;
2614 
2615         if (numFaceCases >= maxFaceCases) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2616         cornersSeen[corners] = 1;
2617 
2618         ierr = DMPlexGetNumFaceVertices_Internal(dm, corners, &nFV);CHKERRQ(ierr);
2619 
2620         numFaceVertices[numFaceCases++] = nFV;
2621       }
2622     }
2623   }
2624   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2625   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2626   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2627   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2628   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2629   /* Count neighboring cells */
2630   for (cell = cStart; cell < cEnd; ++cell) {
2631     PetscInt numNeighbors = maxNeighbors, n;
2632 
2633     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2634     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2635     for (n = 0; n < numNeighbors; ++n) {
2636       PetscInt        cellPair[2];
2637       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2638       PetscInt        meetSize = 0;
2639       const PetscInt *meet    = NULL;
2640 
2641       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2642       if (cellPair[0] == cellPair[1]) continue;
2643       if (!found) {
2644         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2645         if (meetSize) {
2646           PetscInt f;
2647 
2648           for (f = 0; f < numFaceCases; ++f) {
2649             if (numFaceVertices[f] == meetSize) {
2650               found = PETSC_TRUE;
2651               break;
2652             }
2653           }
2654         }
2655         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2656       }
2657       if (found) ++off[cell-cStart+1];
2658     }
2659   }
2660   /* Prefix sum */
2661   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2662 
2663   if (adjacency) {
2664     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2665     /* Get neighboring cells */
2666     for (cell = cStart; cell < cEnd; ++cell) {
2667       PetscInt numNeighbors = maxNeighbors, n;
2668       PetscInt cellOffset   = 0;
2669 
2670       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2671       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2672       for (n = 0; n < numNeighbors; ++n) {
2673         PetscInt        cellPair[2];
2674         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2675         PetscInt        meetSize = 0;
2676         const PetscInt *meet    = NULL;
2677 
2678         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2679         if (cellPair[0] == cellPair[1]) continue;
2680         if (!found) {
2681           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2682           if (meetSize) {
2683             PetscInt f;
2684 
2685             for (f = 0; f < numFaceCases; ++f) {
2686               if (numFaceVertices[f] == meetSize) {
2687                 found = PETSC_TRUE;
2688                 break;
2689               }
2690             }
2691           }
2692           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2693         }
2694         if (found) {
2695           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2696           ++cellOffset;
2697         }
2698       }
2699     }
2700   }
2701   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2702   if (numVertices) *numVertices = numCells;
2703   if (offsets)   *offsets   = off;
2704   if (adjacency) *adjacency = adj;
2705   PetscFunctionReturn(0);
2706 }
2707 
2708 #if defined(PETSC_HAVE_CHACO)
2709 #if defined(PETSC_HAVE_UNISTD_H)
2710 #include <unistd.h>
2711 #endif
2712 /* Chaco does not have an include file */
2713 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2714                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2715                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2716                        int mesh_dims[3], double *goal, int global_method, int local_method,
2717                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2718 
2719 extern int FREE_GRAPH;
2720 
2721 #undef __FUNCT__
2722 #define __FUNCT__ "DMPlexPartition_Chaco"
2723 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2724 {
2725   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2726   MPI_Comm       comm;
2727   int            nvtxs          = numVertices; /* number of vertices in full graph */
2728   int           *vwgts          = NULL;   /* weights for all vertices */
2729   float         *ewgts          = NULL;   /* weights for all edges */
2730   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2731   char          *outassignname  = NULL;   /*  name of assignment output file */
2732   char          *outfilename    = NULL;   /* output file name */
2733   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2734   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2735   int            mesh_dims[3];            /* dimensions of mesh of processors */
2736   double        *goal          = NULL;    /* desired set sizes for each set */
2737   int            global_method = 1;       /* global partitioning algorithm */
2738   int            local_method  = 1;       /* local partitioning algorithm */
2739   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2740   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2741   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2742   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2743   long           seed          = 123636512; /* for random graph mutations */
2744   short int     *assignment;              /* Output partition */
2745   int            fd_stdout, fd_pipe[2];
2746   PetscInt      *points;
2747   PetscMPIInt    commSize;
2748   int            i, v, p;
2749   PetscErrorCode ierr;
2750 
2751   PetscFunctionBegin;
2752   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2753   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2754   if (!numVertices) {
2755     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2756     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2757     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2758     ierr = ISCreateGeneral(comm, 0, NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2759     PetscFunctionReturn(0);
2760   }
2761   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2762   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2763 
2764   if (global_method == INERTIAL_METHOD) {
2765     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2766     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2767   }
2768   mesh_dims[0] = commSize;
2769   mesh_dims[1] = 1;
2770   mesh_dims[2] = 1;
2771   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2772   /* Chaco outputs to stdout. We redirect this to a buffer. */
2773   /* TODO: check error codes for UNIX calls */
2774 #if defined(PETSC_HAVE_UNISTD_H)
2775   {
2776     int piperet;
2777     piperet = pipe(fd_pipe);
2778     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2779     fd_stdout = dup(1);
2780     close(1);
2781     dup2(fd_pipe[1], 1);
2782   }
2783 #endif
2784   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2785                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2786                    vmax, ndims, eigtol, seed);
2787 #if defined(PETSC_HAVE_UNISTD_H)
2788   {
2789     char msgLog[10000];
2790     int  count;
2791 
2792     fflush(stdout);
2793     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2794     if (count < 0) count = 0;
2795     msgLog[count] = 0;
2796     close(1);
2797     dup2(fd_stdout, 1);
2798     close(fd_stdout);
2799     close(fd_pipe[0]);
2800     close(fd_pipe[1]);
2801     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2802   }
2803 #endif
2804   /* Convert to PetscSection+IS */
2805   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2806   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2807   for (v = 0; v < nvtxs; ++v) {
2808     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2809   }
2810   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2811   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2812   for (p = 0, i = 0; p < commSize; ++p) {
2813     for (v = 0; v < nvtxs; ++v) {
2814       if (assignment[v] == p) points[i++] = v;
2815     }
2816   }
2817   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2818   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2819   if (global_method == INERTIAL_METHOD) {
2820     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2821   }
2822   ierr = PetscFree(assignment);CHKERRQ(ierr);
2823   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2824   PetscFunctionReturn(0);
2825 }
2826 #endif
2827 
2828 #if defined(PETSC_HAVE_PARMETIS)
2829 #undef __FUNCT__
2830 #define __FUNCT__ "DMPlexPartition_ParMetis"
2831 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2832 {
2833   PetscFunctionBegin;
2834   SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "ParMetis not yet supported");
2835   PetscFunctionReturn(0);
2836 }
2837 #endif
2838 
2839 #undef __FUNCT__
2840 #define __FUNCT__ "DMPlexEnlargePartition"
2841 /* Expand the partition by BFS on the adjacency graph */
2842 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2843 {
2844   PetscHashI      h;
2845   const PetscInt *points;
2846   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2847   PetscInt        pStart, pEnd, part, q;
2848   PetscErrorCode  ierr;
2849 
2850   PetscFunctionBegin;
2851   PetscHashICreate(h);
2852   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2853   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2854   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2855   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2856   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2857   for (part = pStart; part < pEnd; ++part) {
2858     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2859 
2860     PetscHashIClear(h);
2861     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2862     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2863     /* Add all existing points to h */
2864     for (p = 0; p < numPoints; ++p) {
2865       const PetscInt point = points[off+p];
2866       PetscHashIAdd(h, point, 1);
2867     }
2868     PetscHashISize(h, nP);
2869     if (nP != numPoints) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2870     /* Add all points in next BFS level */
2871     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2872     for (p = 0; p < numPoints; ++p) {
2873       const PetscInt point = points[off+p];
2874       PetscInt       s     = start[point], e = start[point+1], a;
2875 
2876       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2877     }
2878     PetscHashISize(h, numNewPoints);
2879     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2880     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2881     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2882     totPoints += numNewPoints;
2883   }
2884   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2885   PetscHashIDestroy(h);
2886   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2887   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2888   for (part = pStart, q = 0; part < pEnd; ++part) {
2889     PetscInt numPoints, p;
2890 
2891     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2892     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2893     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2894   }
2895   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2896   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2897   PetscFunctionReturn(0);
2898 }
2899 
2900 #undef __FUNCT__
2901 #define __FUNCT__ "DMPlexCreatePartition"
2902 /*
2903   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2904 
2905   Collective on DM
2906 
2907   Input Parameters:
2908   + dm - The DM
2909   . height - The height for points in the partition
2910   - enlarge - Expand each partition with neighbors
2911 
2912   Output Parameters:
2913   + partSection - The PetscSection giving the division of points by partition
2914   . partition - The list of points by partition
2915   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise NULL
2916   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise NULL
2917 
2918   Level: developer
2919 
2920 .seealso DMPlexDistribute()
2921 */
2922 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2923 {
2924   PetscMPIInt    size;
2925   PetscErrorCode ierr;
2926 
2927   PetscFunctionBegin;
2928   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size);CHKERRQ(ierr);
2929 
2930   *origPartSection = NULL;
2931   *origPartition   = NULL;
2932   if (size == 1) {
2933     PetscInt *points;
2934     PetscInt  cStart, cEnd, c;
2935 
2936     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2937     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), partSection);CHKERRQ(ierr);
2938     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2939     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2940     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2941     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2942     for (c = cStart; c < cEnd; ++c) points[c] = c;
2943     ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2944     PetscFunctionReturn(0);
2945   }
2946   if (height == 0) {
2947     PetscInt  numVertices;
2948     PetscInt *start     = NULL;
2949     PetscInt *adjacency = NULL;
2950 
2951     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2952     if (1) {
2953 #if defined(PETSC_HAVE_CHACO)
2954       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2955 #endif
2956     } else {
2957 #if defined(PETSC_HAVE_PARMETIS)
2958       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2959 #endif
2960     }
2961     if (enlarge) {
2962       *origPartSection = *partSection;
2963       *origPartition   = *partition;
2964 
2965       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2966     }
2967     ierr = PetscFree(start);CHKERRQ(ierr);
2968     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2969 # if 0
2970   } else if (height == 1) {
2971     /* Build the dual graph for faces and partition the hypergraph */
2972     PetscInt numEdges;
2973 
2974     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2975     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2976     destroyCSR(numEdges, start, adjacency);
2977 #endif
2978   } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2979   PetscFunctionReturn(0);
2980 }
2981 
2982 #undef __FUNCT__
2983 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2984 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2985 {
2986   /* const PetscInt  height = 0; */
2987   const PetscInt *partArray;
2988   PetscInt       *allPoints, *partPoints = NULL;
2989   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2990   PetscErrorCode  ierr;
2991 
2992   PetscFunctionBegin;
2993   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2994   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2995   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
2996   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2997   for (rank = rStart; rank < rEnd; ++rank) {
2998     PetscInt partSize = 0;
2999     PetscInt numPoints, offset, p;
3000 
3001     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3002     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3003     for (p = 0; p < numPoints; ++p) {
3004       PetscInt  point   = partArray[offset+p], closureSize, c;
3005       PetscInt *closure = NULL;
3006 
3007       /* TODO Include support for height > 0 case */
3008       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3009       /* Merge into existing points */
3010       if (partSize+closureSize > maxPartSize) {
3011         PetscInt *tmpPoints;
3012 
3013         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3014         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3015         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3016         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3017 
3018         partPoints = tmpPoints;
3019       }
3020       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3021       partSize += closureSize;
3022 
3023       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3024       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3025     }
3026     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3027   }
3028   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3029   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3030   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3031 
3032   for (rank = rStart; rank < rEnd; ++rank) {
3033     PetscInt partSize = 0, newOffset;
3034     PetscInt numPoints, offset, p;
3035 
3036     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3037     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3038     for (p = 0; p < numPoints; ++p) {
3039       PetscInt  point   = partArray[offset+p], closureSize, c;
3040       PetscInt *closure = NULL;
3041 
3042       /* TODO Include support for height > 0 case */
3043       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3044       /* Merge into existing points */
3045       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3046       partSize += closureSize;
3047 
3048       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3049       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3050     }
3051     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3052     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3053   }
3054   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3055   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3056   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3057   PetscFunctionReturn(0);
3058 }
3059 
3060 #undef __FUNCT__
3061 #define __FUNCT__ "DMPlexDistributeField"
3062 /*
3063   Input Parameters:
3064 . originalSection
3065 , originalVec
3066 
3067   Output Parameters:
3068 . newSection
3069 . newVec
3070 */
3071 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3072 {
3073   PetscSF        fieldSF;
3074   PetscInt      *remoteOffsets, fieldSize;
3075   PetscScalar   *originalValues, *newValues;
3076   PetscErrorCode ierr;
3077 
3078   PetscFunctionBegin;
3079   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3080 
3081   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3082   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3083   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3084 
3085   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3086   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3087   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3088   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3089   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3090   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3091   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3092   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3093   PetscFunctionReturn(0);
3094 }
3095 
3096 #undef __FUNCT__
3097 #define __FUNCT__ "DMPlexDistribute"
3098 /*@C
3099   DMPlexDistribute - Distributes the mesh and any associated sections.
3100 
3101   Not Collective
3102 
3103   Input Parameter:
3104 + dm  - The original DMPlex object
3105 . partitioner - The partitioning package, or NULL for the default
3106 - overlap - The overlap of partitions, 0 is the default
3107 
3108   Output Parameter:
3109 . parallelMesh - The distributed DMPlex object, or NULL
3110 
3111   Note: If the mesh was not distributed, the return value is NULL
3112 
3113   Level: intermediate
3114 
3115 .keywords: mesh, elements
3116 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3117 @*/
3118 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3119 {
3120   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3121   MPI_Comm               comm;
3122   const PetscInt         height = 0;
3123   PetscInt               dim, numRemoteRanks;
3124   IS                     origCellPart,        cellPart,        part;
3125   PetscSection           origCellPartSection, cellPartSection, partSection;
3126   PetscSFNode           *remoteRanks;
3127   PetscSF                partSF, pointSF, coneSF;
3128   ISLocalToGlobalMapping renumbering;
3129   PetscSection           originalConeSection, newConeSection;
3130   PetscInt              *remoteOffsets;
3131   PetscInt              *cones, *newCones, newConesSize;
3132   PetscBool              flg;
3133   PetscMPIInt            rank, numProcs, p;
3134   PetscErrorCode         ierr;
3135 
3136   PetscFunctionBegin;
3137   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3138   PetscValidPointer(dmParallel,4);
3139 
3140   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3141   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3142   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3143   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3144 
3145   *dmParallel = NULL;
3146   if (numProcs == 1) PetscFunctionReturn(0);
3147 
3148   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3149   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3150   if (overlap > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3151   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3152   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3153   if (!rank) numRemoteRanks = numProcs;
3154   else       numRemoteRanks = 0;
3155   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3156   for (p = 0; p < numRemoteRanks; ++p) {
3157     remoteRanks[p].rank  = p;
3158     remoteRanks[p].index = 0;
3159   }
3160   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3161   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3162   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3163   if (flg) {
3164     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3165     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3166     ierr = ISView(cellPart, NULL);CHKERRQ(ierr);
3167     if (origCellPart) {
3168       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3169       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3170       ierr = ISView(origCellPart, NULL);CHKERRQ(ierr);
3171     }
3172     ierr = PetscSFView(partSF, NULL);CHKERRQ(ierr);
3173   }
3174   /* Close the partition over the mesh */
3175   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3176   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3177   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3178   /* Create new mesh */
3179   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3180   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3181   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3182   pmesh = (DM_Plex*) (*dmParallel)->data;
3183   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3184   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3185   if (flg) {
3186     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3187     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3188     ierr = ISView(part, NULL);CHKERRQ(ierr);
3189     ierr = PetscSFView(pointSF, NULL);CHKERRQ(ierr);
3190     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3191     ierr = ISLocalToGlobalMappingView(renumbering, NULL);CHKERRQ(ierr);
3192   }
3193   /* Distribute cone section */
3194   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3195   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3196   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3197   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3198   {
3199     PetscInt pStart, pEnd, p;
3200 
3201     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3202     for (p = pStart; p < pEnd; ++p) {
3203       PetscInt coneSize;
3204       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3205       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3206     }
3207   }
3208   /* Communicate and renumber cones */
3209   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3210   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3211   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3212   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3213   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3214   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3215   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, NULL, newCones);CHKERRQ(ierr);
3216   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3217   if (flg) {
3218     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3219     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3220     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3221     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3222     ierr = PetscSFView(coneSF, NULL);CHKERRQ(ierr);
3223   }
3224   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3225   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3226   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3227   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3228   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3229   /* Create supports and stratify sieve */
3230   {
3231     PetscInt pStart, pEnd;
3232 
3233     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3234     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3235   }
3236   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3237   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3238   /* Distribute Coordinates */
3239   {
3240     PetscSection originalCoordSection, newCoordSection;
3241     Vec          originalCoordinates, newCoordinates;
3242     const char  *name;
3243 
3244     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3245     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3246     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3247     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3248     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3249     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3250 
3251     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3252     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3253     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3254   }
3255   /* Distribute labels */
3256   {
3257     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3258     PetscInt numLabels = 0, l;
3259 
3260     /* Bcast number of labels */
3261     while (next) {
3262       ++numLabels; next = next->next;
3263     }
3264     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3265     next = mesh->labels;
3266     for (l = 0; l < numLabels; ++l) {
3267       DMLabel         newLabel;
3268       const PetscInt *partArray;
3269       char           *name;
3270       PetscInt       *stratumSizes = NULL, *points = NULL;
3271       PetscMPIInt    *sendcnts     = NULL, *offsets = NULL, *displs = NULL;
3272       PetscInt        nameSize, s, p;
3273       PetscBool       isdepth;
3274       size_t          len = 0;
3275 
3276       /* Bcast name (could filter for no points) */
3277       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3278       nameSize = len;
3279       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3280       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3281       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3282       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3283       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3284       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3285       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3286       newLabel->name = name;
3287       /* Bcast numStrata (could filter for no points in stratum) */
3288       if (!rank) newLabel->numStrata = next->numStrata;
3289       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3290       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3291                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3292                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3293       /* Bcast stratumValues (could filter for no points in stratum) */
3294       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3295       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3296       /* Find size on each process and Scatter */
3297       if (!rank) {
3298         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3299         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3300         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3301         for (s = 0; s < next->numStrata; ++s) {
3302           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3303             const PetscInt point = next->points[p];
3304             PetscInt       proc;
3305 
3306             for (proc = 0; proc < numProcs; ++proc) {
3307               PetscInt dof, off, pPart;
3308 
3309               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3310               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3311               for (pPart = off; pPart < off+dof; ++pPart) {
3312                 if (partArray[pPart] == point) {
3313                   ++stratumSizes[proc*next->numStrata+s];
3314                   break;
3315                 }
3316               }
3317             }
3318           }
3319         }
3320         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3321       }
3322       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3323       /* Calculate stratumOffsets */
3324       newLabel->stratumOffsets[0] = 0;
3325       for (s = 0; s < newLabel->numStrata; ++s) {
3326         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3327       }
3328       /* Pack points and Scatter */
3329       if (!rank) {
3330         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3331         displs[0] = 0;
3332         for (p = 0; p < numProcs; ++p) {
3333           sendcnts[p] = 0;
3334           for (s = 0; s < next->numStrata; ++s) {
3335             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3336           }
3337           offsets[p]  = displs[p];
3338           displs[p+1] = displs[p] + sendcnts[p];
3339         }
3340         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3341         for (s = 0; s < next->numStrata; ++s) {
3342           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3343             const PetscInt point = next->points[p];
3344             PetscInt       proc;
3345 
3346             for (proc = 0; proc < numProcs; ++proc) {
3347               PetscInt dof, off, pPart;
3348 
3349               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3350               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3351               for (pPart = off; pPart < off+dof; ++pPart) {
3352                 if (partArray[pPart] == point) {
3353                   points[offsets[proc]++] = point;
3354                   break;
3355                 }
3356               }
3357             }
3358           }
3359         }
3360       }
3361       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3362       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3363       ierr = PetscFree(points);CHKERRQ(ierr);
3364       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3365       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3366       /* Renumber points */
3367       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, NULL, newLabel->points);CHKERRQ(ierr);
3368       /* Sort points */
3369       for (s = 0; s < newLabel->numStrata; ++s) {
3370         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3371       }
3372       /* Insert into list */
3373       if (newNext) newNext->next = newLabel;
3374       else pmesh->labels = newLabel;
3375       newNext = newLabel;
3376       if (!rank) next = next->next;
3377     }
3378   }
3379   /* Cleanup Partition */
3380   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3381   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3382   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3383   ierr = ISDestroy(&part);CHKERRQ(ierr);
3384   /* Create point SF for parallel mesh */
3385   {
3386     const PetscInt *leaves;
3387     PetscSFNode    *remotePoints, *rowners, *lowners;
3388     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3389     PetscInt        pStart, pEnd;
3390 
3391     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3392     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, NULL);CHKERRQ(ierr);
3393     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3394     for (p=0; p<numRoots; p++) {
3395       rowners[p].rank  = -1;
3396       rowners[p].index = -1;
3397     }
3398     if (origCellPart) {
3399       /* Make sure cells in the original partition are not assigned to other procs */
3400       const PetscInt *origCells;
3401 
3402       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3403       for (p = 0; p < numProcs; ++p) {
3404         PetscInt dof, off, d;
3405 
3406         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3407         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3408         for (d = off; d < off+dof; ++d) {
3409           rowners[origCells[d]].rank = p;
3410         }
3411       }
3412       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3413     }
3414     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3415     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3416 
3417     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3418     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3419     for (p = 0; p < numLeaves; ++p) {
3420       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3421         lowners[p].rank  = rank;
3422         lowners[p].index = leaves ? leaves[p] : p;
3423       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3424         lowners[p].rank  = -2;
3425         lowners[p].index = -2;
3426       }
3427     }
3428     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3429       rowners[p].rank  = -3;
3430       rowners[p].index = -3;
3431     }
3432     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3433     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3434     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3435     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3436     for (p = 0; p < numLeaves; ++p) {
3437       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3438       if (lowners[p].rank != rank) ++numGhostPoints;
3439     }
3440     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3441     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3442     for (p = 0, gp = 0; p < numLeaves; ++p) {
3443       if (lowners[p].rank != rank) {
3444         ghostPoints[gp]        = leaves ? leaves[p] : p;
3445         remotePoints[gp].rank  = lowners[p].rank;
3446         remotePoints[gp].index = lowners[p].index;
3447         ++gp;
3448       }
3449     }
3450     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3451     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3452     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3453   }
3454   /* Cleanup */
3455   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3456   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3457   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3458   PetscFunctionReturn(0);
3459 }
3460 
3461 #undef __FUNCT__
3462 #define __FUNCT__ "DMPlexRenumber_Private"
3463 /*
3464   Reasons to renumber:
3465 
3466   1) Permute points, e.g. bandwidth reduction (Renumber)
3467 
3468     a) Must not mix strata
3469 
3470   2) Shift numbers for point insertion (Shift)
3471 
3472     a) Want operation brken into parts so that insertion can be interleaved
3473 
3474   renumbering - An IS which provides the new numbering
3475 */
3476 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3477 {
3478   PetscFunctionBegin;
3479   PetscFunctionReturn(0);
3480 }
3481 
3482 #undef __FUNCT__
3483 #define __FUNCT__ "DMPlexShiftPoint_Private"
3484 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3485 {
3486   if (depth < 0) return p;
3487   /* Cells    */ if (p < depthEnd[depth])   return p;
3488   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3489   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3490   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3491 }
3492 
3493 #undef __FUNCT__
3494 #define __FUNCT__ "DMPlexShiftSizes_Private"
3495 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3496 {
3497   PetscInt      *depthEnd;
3498   PetscInt       depth = 0, d, pStart, pEnd, p;
3499   PetscErrorCode ierr;
3500 
3501   PetscFunctionBegin;
3502   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3503   if (depth < 0) PetscFunctionReturn(0);
3504   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3505   /* Step 1: Expand chart */
3506   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3507   for (d = 0; d <= depth; ++d) {
3508     pEnd += depthShift[d];
3509     ierr  = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3510   }
3511   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3512   /* Step 2: Set cone and support sizes */
3513   for (d = 0; d <= depth; ++d) {
3514     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3515     for (p = pStart; p < pEnd; ++p) {
3516       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3517       PetscInt size;
3518 
3519       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3520       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3521       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3522       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3523     }
3524   }
3525   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3526   PetscFunctionReturn(0);
3527 }
3528 
3529 #undef __FUNCT__
3530 #define __FUNCT__ "DMPlexShiftPoints_Private"
3531 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3532 {
3533   PetscInt      *depthEnd, *newpoints;
3534   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3535   PetscErrorCode ierr;
3536 
3537   PetscFunctionBegin;
3538   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3539   if (depth < 0) PetscFunctionReturn(0);
3540   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3541   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3542   for (d = 0; d <= depth; ++d) {
3543     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3544   }
3545   /* Step 5: Set cones and supports */
3546   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3547   for (p = pStart; p < pEnd; ++p) {
3548     const PetscInt *points = NULL, *orientations = NULL;
3549     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3550 
3551     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3552     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3553     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3554     for (i = 0; i < size; ++i) {
3555       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3556     }
3557     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3558     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3559     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3560     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3561     for (i = 0; i < size; ++i) {
3562       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3563     }
3564     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3565   }
3566   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3567   PetscFunctionReturn(0);
3568 }
3569 
3570 #undef __FUNCT__
3571 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3572 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3573 {
3574   PetscSection   coordSection, newCoordSection;
3575   Vec            coordinates, newCoordinates;
3576   PetscScalar   *coords, *newCoords;
3577   PetscInt      *depthEnd, coordSize;
3578   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3579   PetscErrorCode ierr;
3580 
3581   PetscFunctionBegin;
3582   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3583   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3584   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3585   for (d = 0; d <= depth; ++d) {
3586     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3587   }
3588   /* Step 8: Convert coordinates */
3589   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3590   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3591   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3592   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newCoordSection);CHKERRQ(ierr);
3593   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3594   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3595   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3596   for (v = vStartNew; v < vEndNew; ++v) {
3597     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3598     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3599   }
3600   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3601   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3602   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3603   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &newCoordinates);CHKERRQ(ierr);
3604   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3605   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3606   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3607   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3608   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3609   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3610   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3611   for (v = vStart; v < vEnd; ++v) {
3612     PetscInt dof, off, noff, d;
3613 
3614     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3615     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3616     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3617     for (d = 0; d < dof; ++d) {
3618       newCoords[noff+d] = coords[off+d];
3619     }
3620   }
3621   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3622   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3623   ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3624   ierr = PetscSectionDestroy(&newCoordSection);CHKERRQ(ierr);
3625   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3626   PetscFunctionReturn(0);
3627 }
3628 
3629 #undef __FUNCT__
3630 #define __FUNCT__ "DMPlexShiftSF_Private"
3631 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3632 {
3633   PetscInt          *depthEnd;
3634   PetscInt           depth = 0, d;
3635   PetscSF            sfPoint, sfPointNew;
3636   const PetscSFNode *remotePoints;
3637   PetscSFNode       *gremotePoints;
3638   const PetscInt    *localPoints;
3639   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3640   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3641   PetscMPIInt        numProcs;
3642   PetscErrorCode     ierr;
3643 
3644   PetscFunctionBegin;
3645   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3646   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3647   for (d = 0; d <= depth; ++d) {
3648     totShift += depthShift[d];
3649     ierr      = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3650   }
3651   /* Step 9: Convert pointSF */
3652   ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
3653   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3654   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3655   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3656   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3657   if (numRoots >= 0) {
3658     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3659     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3660     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3661     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3662     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3663     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3664     for (l = 0; l < numLeaves; ++l) {
3665       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3666       gremotePoints[l].rank  = remotePoints[l].rank;
3667       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3668     }
3669     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3670     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3671   }
3672   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3673   PetscFunctionReturn(0);
3674 }
3675 
3676 #undef __FUNCT__
3677 #define __FUNCT__ "DMPlexShiftLabels_Private"
3678 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3679 {
3680   PetscSF            sfPoint;
3681   DMLabel            vtkLabel, ghostLabel;
3682   PetscInt          *depthEnd;
3683   const PetscSFNode *leafRemote;
3684   const PetscInt    *leafLocal;
3685   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3686   PetscMPIInt        rank;
3687   PetscErrorCode     ierr;
3688 
3689   PetscFunctionBegin;
3690   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3691   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3692   for (d = 0; d <= depth; ++d) {
3693     ierr = DMPlexGetDepthStratum(dm, d, NULL, &depthEnd[d]);CHKERRQ(ierr);
3694   }
3695   /* Step 10: Convert labels */
3696   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3697   for (l = 0; l < numLabels; ++l) {
3698     DMLabel         label, newlabel;
3699     const char     *lname;
3700     PetscBool       isDepth;
3701     IS              valueIS;
3702     const PetscInt *values;
3703     PetscInt        numValues, val;
3704 
3705     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3706     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3707     if (isDepth) continue;
3708     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3709     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3710     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3711     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3712     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3713     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3714     for (val = 0; val < numValues; ++val) {
3715       IS              pointIS;
3716       const PetscInt *points;
3717       PetscInt        numPoints, p;
3718 
3719       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3720       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3721       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3722       for (p = 0; p < numPoints; ++p) {
3723         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3724 
3725         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3726       }
3727       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3728       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3729     }
3730     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3731     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3732   }
3733   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3734   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3735   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
3736   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3737   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3738   ierr = PetscSFGetGraph(sfPoint, NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3739   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3740   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3741   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3742   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3743   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3744     for (; c < leafLocal[l] && c < cEnd; ++c) {
3745       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3746     }
3747     if (leafLocal[l] >= cEnd) break;
3748     if (leafRemote[l].rank == rank) {
3749       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3750     } else {
3751       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3752     }
3753   }
3754   for (; c < cEnd; ++c) {
3755     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3756   }
3757   if (0) {
3758     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3759     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3760     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3761   }
3762   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3763   for (f = fStart; f < fEnd; ++f) {
3764     PetscInt numCells;
3765 
3766     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3767     if (numCells < 2) {
3768       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3769     } else {
3770       const PetscInt *cells = NULL;
3771       PetscInt        vA, vB;
3772 
3773       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3774       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3775       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3776       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3777     }
3778   }
3779   if (0) {
3780     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3781     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3782     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3783   }
3784   PetscFunctionReturn(0);
3785 }
3786 
3787 #undef __FUNCT__
3788 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3789 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3790 {
3791   DMLabel         label;
3792   IS              valueIS;
3793   const PetscInt *values;
3794   PetscInt       *depthShift;
3795   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3796   PetscErrorCode  ierr;
3797 
3798   PetscFunctionBegin;
3799   /* Count ghost cells */
3800   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3801   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3802   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3803   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3804 
3805   *numGhostCells = 0;
3806   for (fs = 0; fs < numFS; ++fs) {
3807     PetscInt numBdFaces;
3808 
3809     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3810 
3811     *numGhostCells += numBdFaces;
3812   }
3813   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3814   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3815   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3816   if (depth >= 0) depthShift[depth] = *numGhostCells;
3817   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3818   /* Step 3: Set cone/support sizes for new points */
3819   ierr = DMPlexGetHeightStratum(dm, 0, NULL, &cEnd);CHKERRQ(ierr);
3820   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3821     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3822   }
3823   for (fs = 0; fs < numFS; ++fs) {
3824     IS              faceIS;
3825     const PetscInt *faces;
3826     PetscInt        numFaces, f;
3827 
3828     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3829     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3830     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3831     for (f = 0; f < numFaces; ++f) {
3832       PetscInt size;
3833 
3834       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3835       if (size != 1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3836       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3837     }
3838     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3839     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3840   }
3841   /* Step 4: Setup ghosted DM */
3842   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3843   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3844   /* Step 6: Set cones and supports for new points */
3845   ghostCell = cEnd;
3846   for (fs = 0; fs < numFS; ++fs) {
3847     IS              faceIS;
3848     const PetscInt *faces;
3849     PetscInt        numFaces, f;
3850 
3851     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3852     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3853     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3854     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3855       PetscInt newFace = faces[f] + *numGhostCells;
3856 
3857       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3858       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3859     }
3860     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3861     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3862   }
3863   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3864   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3865   /* Step 7: Stratify */
3866   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3867   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3868   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3869   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3870   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3871   PetscFunctionReturn(0);
3872 }
3873 
3874 #undef __FUNCT__
3875 #define __FUNCT__ "DMPlexConstructGhostCells"
3876 /*@C
3877   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3878 
3879   Collective on dm
3880 
3881   Input Parameters:
3882 + dm - The original DM
3883 - labelName - The label specifying the boundary faces (this could be auto-generated)
3884 
3885   Output Parameters:
3886 + numGhostCells - The number of ghost cells added to the DM
3887 - dmGhosted - The new DM
3888 
3889   Level: developer
3890 
3891 .seealso: DMCreate()
3892 */
3893 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3894 {
3895   DM             gdm;
3896   PetscInt       dim;
3897   PetscErrorCode ierr;
3898 
3899   PetscFunctionBegin;
3900   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3901   PetscValidPointer(numGhostCells, 3);
3902   PetscValidPointer(dmGhosted, 4);
3903   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &gdm);CHKERRQ(ierr);
3904   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3905   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3906   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3907   switch (dim) {
3908   case 2:
3909     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3910     break;
3911   default:
3912     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3913   }
3914   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3915   *dmGhosted = gdm;
3916   PetscFunctionReturn(0);
3917 }
3918 
3919 #undef __FUNCT__
3920 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3921 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, DMLabel label, DM sdm)
3922 {
3923   MPI_Comm        comm;
3924   IS              valueIS, *pointIS;
3925   const PetscInt *values, **splitPoints;
3926   PetscSection    coordSection;
3927   Vec             coordinates;
3928   PetscScalar    *coords;
3929   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3930   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3931   PetscErrorCode  ierr;
3932 
3933   PetscFunctionBegin;
3934   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
3935   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3936   /* Count split points and add cohesive cells */
3937   if (label) {
3938     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3939     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3940     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3941   }
3942   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3943   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3944   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3945   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3946   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3947   for (d = 0; d <= depth; ++d) {
3948     ierr              = DMPlexGetDepthStratum(dm, d, NULL, &pMaxNew[d]);CHKERRQ(ierr);
3949     numSplitPoints[d] = 0;
3950     splitPoints[d]    = NULL;
3951     pointIS[d]        = NULL;
3952   }
3953   for (sp = 0; sp < numSP; ++sp) {
3954     const PetscInt dep = values[sp];
3955 
3956     if ((dep < 0) || (dep > depth)) continue;
3957     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3958     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3959     if (pointIS[dep]) {
3960       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3961       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3962     }
3963   }
3964   if (depth >= 0) {
3965     /* Calculate number of additional points */
3966     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3967     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3968     /* Calculate hybrid bound for each dimension */
3969     pMaxNew[0] += depthShift[depth];
3970     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3971     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3972 
3973     /* Calculate point offset for each dimension */
3974     depthOffset[depth] = 0;
3975     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3976     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3977     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3978   }
3979   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3980   /* Step 3: Set cone/support sizes for new points */
3981   for (dep = 0; dep <= depth; ++dep) {
3982     for (p = 0; p < numSplitPoints[dep]; ++p) {
3983       const PetscInt  oldp   = splitPoints[dep][p];
3984       const PetscInt  newp   = depthOffset[dep] + oldp;
3985       const PetscInt  splitp = pMaxNew[dep] + p;
3986       const PetscInt *support;
3987       PetscInt        coneSize, supportSize, q, e;
3988 
3989       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3990       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3991       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3992       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3993       if (dep == depth-1) {
3994         const PetscInt ccell = pMaxNew[depth] + p;
3995         /* Add cohesive cells, they are prisms */
3996         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3997       } else if (dep == 0) {
3998         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3999 
4000         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4001         /* Split old vertex: Edges in old split faces and new cohesive edge */
4002         for (e = 0, q = 0; e < supportSize; ++e) {
4003           PetscInt val;
4004 
4005           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4006           if ((val == 1) || (val == (shift + 1))) ++q;
4007         }
4008         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
4009         /* Split new vertex: Edges in new split faces and new cohesive edge */
4010         for (e = 0, q = 0; e < supportSize; ++e) {
4011           PetscInt val;
4012 
4013           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4014           if ((val == 1) || (val == -(shift + 1))) ++q;
4015         }
4016         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4017         /* Add cohesive edges */
4018         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4019         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4020       } else if (dep == dim-2) {
4021         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4022         /* Split old edge: Faces in positive side cells and old split faces */
4023         for (e = 0, q = 0; e < supportSize; ++e) {
4024           PetscInt val;
4025 
4026           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4027           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4028         }
4029         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4030         /* Split new edge: Faces in negative side cells and new split faces */
4031         for (e = 0, q = 0; e < supportSize; ++e) {
4032           PetscInt val;
4033 
4034           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4035           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4036         }
4037         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4038       }
4039     }
4040   }
4041   /* Step 4: Setup split DM */
4042   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4043   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4044   /* Step 6: Set cones and supports for new points */
4045   for (dep = 0; dep <= depth; ++dep) {
4046     for (p = 0; p < numSplitPoints[dep]; ++p) {
4047       const PetscInt  oldp   = splitPoints[dep][p];
4048       const PetscInt  newp   = depthOffset[dep] + oldp;
4049       const PetscInt  splitp = pMaxNew[dep] + p;
4050       const PetscInt *cone, *support, *ornt;
4051       PetscInt        coneSize, supportSize, q, v, e, s;
4052 
4053       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4054       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4055       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4056       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4057       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4058       if (dep == depth-1) {
4059         const PetscInt  ccell = pMaxNew[depth] + p;
4060         const PetscInt *supportF;
4061 
4062         /* Split face:       copy in old face to new face to start */
4063         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4064         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4065         /* Split old face:   old vertices/edges in cone so no change */
4066         /* Split new face:   new vertices/edges in cone */
4067         for (q = 0; q < coneSize; ++q) {
4068           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4069 
4070           coneNew[2+q] = pMaxNew[dim-2] + v;
4071         }
4072         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4073         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4074         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4075         coneNew[0] = newp;
4076         coneNew[1] = splitp;
4077         for (q = 0; q < coneSize; ++q) {
4078           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4079         }
4080         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4081 
4082 
4083         for (s = 0; s < supportSize; ++s) {
4084           PetscInt val;
4085 
4086           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4087           if (val < 0) {
4088             /* Split old face:   Replace negative side cell with cohesive cell */
4089             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4090           } else {
4091             /* Split new face:   Replace positive side cell with cohesive cell */
4092             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4093           }
4094         }
4095       } else if (dep == 0) {
4096         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4097 
4098         /* Split old vertex: Edges in old split faces and new cohesive edge */
4099         for (e = 0, q = 0; e < supportSize; ++e) {
4100           PetscInt val;
4101 
4102           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4103           if ((val == 1) || (val == (shift + 1))) {
4104             supportNew[q++] = depthOffset[1] + support[e];
4105           }
4106         }
4107         supportNew[q] = cedge;
4108 
4109         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4110         /* Split new vertex: Edges in new split faces and new cohesive edge */
4111         for (e = 0, q = 0; e < supportSize; ++e) {
4112           PetscInt val, edge;
4113 
4114           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4115           if (val == 1) {
4116             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4117             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4118             supportNew[q++] = pMaxNew[1] + edge;
4119           } else if (val == -(shift + 1)) {
4120             supportNew[q++] = depthOffset[1] + support[e];
4121           }
4122         }
4123         supportNew[q] = cedge;
4124         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4125         /* Cohesive edge:    Old and new split vertex, punting on support */
4126         coneNew[0] = newp;
4127         coneNew[1] = splitp;
4128         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4129       } else if (dep == dim-2) {
4130         /* Split old edge:   old vertices in cone so no change */
4131         /* Split new edge:   new vertices in cone */
4132         for (q = 0; q < coneSize; ++q) {
4133           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4134 
4135           coneNew[q] = pMaxNew[dim-3] + v;
4136         }
4137         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4138         /* Split old edge: Faces in positive side cells and old split faces */
4139         for (e = 0, q = 0; e < supportSize; ++e) {
4140           PetscInt val;
4141 
4142           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4143           if ((val == dim-1) || (val == (shift + dim-1))) {
4144             supportNew[q++] = depthOffset[dim-1] + support[e];
4145           }
4146         }
4147         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4148         /* Split new edge: Faces in negative side cells and new split faces */
4149         for (e = 0, q = 0; e < supportSize; ++e) {
4150           PetscInt val, face;
4151 
4152           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4153           if (val == dim-1) {
4154             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4155             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4156             supportNew[q++] = pMaxNew[dim-1] + face;
4157           } else if (val == -(shift + dim-1)) {
4158             supportNew[q++] = depthOffset[dim-1] + support[e];
4159           }
4160         }
4161         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4162       }
4163     }
4164   }
4165   /* Step 6b: Replace split points in negative side cones */
4166   for (sp = 0; sp < numSP; ++sp) {
4167     PetscInt        dep = values[sp];
4168     IS              pIS;
4169     PetscInt        numPoints;
4170     const PetscInt *points;
4171 
4172     if (dep >= 0) continue;
4173     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4174     if (!pIS) continue;
4175     dep  = -dep - shift;
4176     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4177     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4178     for (p = 0; p < numPoints; ++p) {
4179       const PetscInt  oldp = points[p];
4180       const PetscInt  newp = depthOffset[dep] + oldp;
4181       const PetscInt *cone;
4182       PetscInt        coneSize, c;
4183       PetscBool       replaced = PETSC_FALSE;
4184 
4185       /* Negative edge: replace split vertex */
4186       /* Negative cell: replace split face */
4187       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4188       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4189       for (c = 0; c < coneSize; ++c) {
4190         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4191         PetscInt       csplitp, cp, val;
4192 
4193         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4194         if (val == dep-1) {
4195           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4196           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4197           csplitp  = pMaxNew[dep-1] + cp;
4198           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4199           replaced = PETSC_TRUE;
4200         }
4201       }
4202       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4203     }
4204     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4205     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4206   }
4207   /* Step 7: Stratify */
4208   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4209   /* Step 8: Coordinates */
4210   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4211   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4212   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4213   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4214   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4215     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4216     const PetscInt splitp = pMaxNew[0] + v;
4217     PetscInt       dof, off, soff, d;
4218 
4219     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4220     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4221     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4222     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4223   }
4224   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4225   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4226   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4227   /* Step 10: Labels */
4228   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4229   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4230   for (dep = 0; dep <= depth; ++dep) {
4231     for (p = 0; p < numSplitPoints[dep]; ++p) {
4232       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4233       const PetscInt splitp = pMaxNew[dep] + p;
4234       PetscInt       l;
4235 
4236       for (l = 0; l < numLabels; ++l) {
4237         DMLabel     mlabel;
4238         const char *lname;
4239         PetscInt    val;
4240 
4241         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4242         ierr = DMPlexGetLabel(sdm, lname, &mlabel);CHKERRQ(ierr);
4243         ierr = DMLabelGetValue(mlabel, newp, &val);CHKERRQ(ierr);
4244         if (val >= 0) {
4245           ierr = DMLabelSetValue(mlabel, splitp, val);CHKERRQ(ierr);
4246           if (dep == 0) {
4247             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4248             ierr = DMLabelSetValue(mlabel, cedge, val);CHKERRQ(ierr);
4249           }
4250         }
4251       }
4252     }
4253   }
4254   for (sp = 0; sp < numSP; ++sp) {
4255     const PetscInt dep = values[sp];
4256 
4257     if ((dep < 0) || (dep > depth)) continue;
4258     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4259     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4260   }
4261   if (label) {
4262     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4263     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4264   }
4265   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4266   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4267   PetscFunctionReturn(0);
4268 }
4269 
4270 #undef __FUNCT__
4271 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4272 /*@C
4273   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4274 
4275   Collective on dm
4276 
4277   Input Parameters:
4278 + dm - The original DM
4279 - labelName - The label specifying the boundary faces (this could be auto-generated)
4280 
4281   Output Parameters:
4282 - dmSplit - The new DM
4283 
4284   Level: developer
4285 
4286 .seealso: DMCreate()
4287 */
4288 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, DMLabel label, DM *dmSplit)
4289 {
4290   DM             sdm;
4291   PetscInt       dim;
4292   PetscErrorCode ierr;
4293 
4294   PetscFunctionBegin;
4295   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4296   PetscValidPointer(dmSplit, 4);
4297   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &sdm);CHKERRQ(ierr);
4298   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4299   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4300   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4301   switch (dim) {
4302   case 2:
4303   case 3:
4304     ierr = DMPlexConstructCohesiveCells_Private(dm, label, sdm);CHKERRQ(ierr);
4305     break;
4306   default:
4307     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4308   }
4309   *dmSplit = sdm;
4310   PetscFunctionReturn(0);
4311 }
4312 
4313 #undef __FUNCT__
4314 #define __FUNCT__ "DMLabelCohesiveComplete"
4315 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4316 {
4317   IS              dimIS;
4318   const PetscInt *points;
4319   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4320   PetscErrorCode  ierr;
4321 
4322   PetscFunctionBegin;
4323   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4324   /* Cell orientation for face gives the side of the fault */
4325   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4326   if (!dimIS) PetscFunctionReturn(0);
4327   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4328   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4329   for (p = 0; p < numPoints; ++p) {
4330     const PetscInt *support;
4331     PetscInt        supportSize, s;
4332 
4333     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4334     if (supportSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4335     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4336     for (s = 0; s < supportSize; ++s) {
4337       const PetscInt *cone, *ornt;
4338       PetscInt        coneSize, c;
4339       PetscBool       pos = PETSC_TRUE;
4340 
4341       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4342       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4343       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4344       for (c = 0; c < coneSize; ++c) {
4345         if (cone[c] == points[p]) {
4346           if (ornt[c] >= 0) {
4347             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4348           } else {
4349             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4350             pos  = PETSC_FALSE;
4351           }
4352           break;
4353         }
4354       }
4355       if (c == coneSize) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4356       /* Put faces touching the fault in the label */
4357       for (c = 0; c < coneSize; ++c) {
4358         const PetscInt point = cone[c];
4359 
4360         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4361         if (val == -1) {
4362           PetscInt *closure = NULL;
4363           PetscInt  closureSize, cl;
4364 
4365           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4366           for (cl = 0; cl < closureSize*2; cl += 2) {
4367             const PetscInt clp = closure[cl];
4368 
4369             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4370             if ((val >= 0) && (val < dim-1)) {
4371               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4372               break;
4373             }
4374           }
4375           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4376         }
4377       }
4378     }
4379   }
4380   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4381   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4382   /* Search for other cells/faces/edges connected to the fault by a vertex */
4383   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4384   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4385   if (!dimIS) PetscFunctionReturn(0);
4386   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4387   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4388   for (p = 0; p < numPoints; ++p) {
4389     PetscInt *star = NULL;
4390     PetscInt  starSize, s;
4391     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4392 
4393     /* First mark cells connected to the fault */
4394     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4395     while (again) {
4396       if (again > 1) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4397       again = 0;
4398       for (s = 0; s < starSize*2; s += 2) {
4399         const PetscInt  point = star[s];
4400         const PetscInt *cone;
4401         PetscInt        coneSize, c;
4402 
4403         if ((point < cStart) || (point >= cEnd)) continue;
4404         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4405         if (val != -1) continue;
4406         again = 2;
4407         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4408         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4409         for (c = 0; c < coneSize; ++c) {
4410           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4411           if (val != -1) {
4412             if (abs(val) < shift) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4413             if (val > 0) {
4414               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4415             } else {
4416               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4417             }
4418             again = 1;
4419             break;
4420           }
4421         }
4422       }
4423     }
4424     /* Classify the rest by cell membership */
4425     for (s = 0; s < starSize*2; s += 2) {
4426       const PetscInt point = star[s];
4427 
4428       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4429       if (val == -1) {
4430         PetscInt  *sstar = NULL;
4431         PetscInt   sstarSize, ss;
4432         PetscBool  marked = PETSC_FALSE;
4433 
4434         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4435         for (ss = 0; ss < sstarSize*2; ss += 2) {
4436           const PetscInt spoint = sstar[ss];
4437 
4438           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4439           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4440           if (val == -1) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4441           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4442           if (val > 0) {
4443             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4444           } else {
4445             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4446           }
4447           marked = PETSC_TRUE;
4448           break;
4449         }
4450         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4451         if (!marked) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d could not be classified", point);
4452       }
4453     }
4454     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4455   }
4456   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4457   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4458   PetscFunctionReturn(0);
4459 }
4460 
4461 #undef __FUNCT__
4462 #define __FUNCT__ "DMPlexInterpolate_2D"
4463 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4464 {
4465   DM             idm;
4466   DM_Plex       *mesh;
4467   PetscHashIJ    edgeTable;
4468   PetscInt      *off;
4469   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4470   PetscInt       numEdges, firstEdge, edge, e;
4471   PetscErrorCode ierr;
4472 
4473   PetscFunctionBegin;
4474   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4475   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4476   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4477   numCells    = cEnd - cStart;
4478   numVertices = vEnd - vStart;
4479   firstEdge   = numCells + numVertices;
4480   numEdges    = 0;
4481   /* Count edges using algorithm from CreateNeighborCSR */
4482   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4483   if (off) {
4484     PetscInt numCorners = 0;
4485 
4486     numEdges = off[numCells]/2;
4487 #if 0
4488     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4489     numEdges += 3*numCells - off[numCells];
4490 #else
4491     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4492     for (c = cStart; c < cEnd; ++c) {
4493       PetscInt coneSize;
4494 
4495       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4496       numCorners += coneSize;
4497     }
4498     numEdges += numCorners - off[numCells];
4499 #endif
4500   }
4501 #if 0
4502   /* Check Euler characteristic V - E + F = 1 */
4503   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4504 #endif
4505   /* Create interpolated mesh */
4506   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &idm);CHKERRQ(ierr);
4507   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4508   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4509   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4510   for (c = 0; c < numCells; ++c) {
4511     PetscInt numCorners;
4512 
4513     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4514     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4515   }
4516   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4517     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4518   }
4519   ierr = DMSetUp(idm);CHKERRQ(ierr);
4520   /* Get edge cones from subsets of cell vertices */
4521   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4522   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4523 
4524   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4525     const PetscInt *cellFaces;
4526     PetscInt        numCellFaces, faceSize, cf;
4527 
4528     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4529     if (faceSize != 2) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4530     for (cf = 0; cf < numCellFaces; ++cf) {
4531 #if 1
4532       PetscHashIJKey key;
4533 
4534       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4535       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4536       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4537       if (e < 0) {
4538         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4539         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4540         e    = edge++;
4541       }
4542 #else
4543       PetscBool found = PETSC_FALSE;
4544 
4545       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4546       for (e = firstEdge; e < edge; ++e) {
4547         const PetscInt *cone;
4548 
4549         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4550         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4551             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4552           found = PETSC_TRUE;
4553           break;
4554         }
4555       }
4556       if (!found) {
4557         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4558         ++edge;
4559       }
4560 #endif
4561       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4562     }
4563   }
4564   if (edge != firstEdge+numEdges) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4565   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4566   ierr = PetscFree(off);CHKERRQ(ierr);
4567   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4568   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4569   mesh = (DM_Plex*) (idm)->data;
4570   /* Orient edges */
4571   for (c = 0; c < numCells; ++c) {
4572     const PetscInt *cone = NULL, *cellFaces;
4573     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4574 
4575     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4576     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4577     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4578     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4579     if (coneSize != numCellFaces) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4580     for (cf = 0; cf < numCellFaces; ++cf) {
4581       const PetscInt *econe = NULL;
4582       PetscInt        esize;
4583 
4584       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4585       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4586       if (esize != 2) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4587       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4588         /* Correctly oriented */
4589         mesh->coneOrientations[coff+cf] = 0;
4590       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4591         /* Start at index 1, and reverse orientation */
4592         mesh->coneOrientations[coff+cf] = -(1+1);
4593       }
4594     }
4595   }
4596   *dmInt = idm;
4597   PetscFunctionReturn(0);
4598 }
4599 
4600 #undef __FUNCT__
4601 #define __FUNCT__ "DMPlexInterpolate_3D"
4602 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4603 {
4604   DM             idm, fdm;
4605   DM_Plex       *mesh;
4606   PetscInt      *off;
4607   const PetscInt numCorners = 4;
4608   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4609   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4610   PetscErrorCode ierr;
4611 
4612   PetscFunctionBegin;
4613   {
4614     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4615     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4616     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4617   }
4618   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4619   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4620   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4621   numCells    = cEnd - cStart;
4622   numVertices = vEnd - vStart;
4623   firstFace   = numCells + numVertices;
4624   numFaces    = 0;
4625   /* Count faces using algorithm from CreateNeighborCSR */
4626   ierr = DMPlexCreateNeighborCSR(dm, NULL, &off, NULL);CHKERRQ(ierr);
4627   if (off) {
4628     numFaces = off[numCells]/2;
4629     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4630     numFaces += 4*numCells - off[numCells];
4631   }
4632   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4633   firstEdge = firstFace + numFaces;
4634   numEdges  = numVertices + numFaces - numCells - 1;
4635   /* Create interpolated mesh */
4636   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &idm);CHKERRQ(ierr);
4637   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4638   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4639   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4640   for (c = 0; c < numCells; ++c) {
4641     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4642   }
4643   for (f = firstFace; f < firstFace+numFaces; ++f) {
4644     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4645   }
4646   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4647     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4648   }
4649   ierr = DMSetUp(idm);CHKERRQ(ierr);
4650   /* Get face cones from subsets of cell vertices */
4651   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &fdm);CHKERRQ(ierr);
4652   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4653   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4654   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4655   for (f = firstFace; f < firstFace+numFaces; ++f) {
4656     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4657   }
4658   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4659   for (c = 0, face = firstFace; c < numCells; ++c) {
4660     const PetscInt *cellFaces;
4661     PetscInt        numCellFaces, faceSize, cf;
4662 
4663     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4664     if (faceSize != 3) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4665     for (cf = 0; cf < numCellFaces; ++cf) {
4666       PetscBool found = PETSC_FALSE;
4667 
4668       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4669       for (f = firstFace; f < face; ++f) {
4670         const PetscInt *cone = NULL;
4671 
4672         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4673         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4674             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4675             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4676             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4677             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4678             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4679           found = PETSC_TRUE;
4680           break;
4681         }
4682       }
4683       if (!found) {
4684         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4685         /* Save the vertices for orientation calculation */
4686         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4687         ++face;
4688       }
4689       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4690     }
4691   }
4692   if (face != firstFace+numFaces) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4693   /* Get edge cones from subsets of face vertices */
4694   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4695     const PetscInt *cellFaces;
4696     PetscInt        numCellFaces, faceSize, cf;
4697 
4698     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4699     if (faceSize != 2) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4700     for (cf = 0; cf < numCellFaces; ++cf) {
4701       PetscBool found = PETSC_FALSE;
4702 
4703       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4704       for (e = firstEdge; e < edge; ++e) {
4705         const PetscInt *cone = NULL;
4706 
4707         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4708         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4709             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4710           found = PETSC_TRUE;
4711           break;
4712         }
4713       }
4714       if (!found) {
4715         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4716         ++edge;
4717       }
4718       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4719     }
4720   }
4721   if (edge != firstEdge+numEdges) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4722   ierr = PetscFree(off);CHKERRQ(ierr);
4723   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4724   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4725   mesh = (DM_Plex*) (idm)->data;
4726   /* Orient edges */
4727   for (f = firstFace; f < firstFace+numFaces; ++f) {
4728     const PetscInt *cone, *cellFaces;
4729     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4730 
4731     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4732     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4733     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4734     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4735     if (coneSize != numCellFaces) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4736     for (cf = 0; cf < numCellFaces; ++cf) {
4737       const PetscInt *econe;
4738       PetscInt        esize;
4739 
4740       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4741       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4742       if (esize != 2) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4743       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4744         /* Correctly oriented */
4745         mesh->coneOrientations[coff+cf] = 0;
4746       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4747         /* Start at index 1, and reverse orientation */
4748         mesh->coneOrientations[coff+cf] = -(1+1);
4749       }
4750     }
4751   }
4752   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4753   /* Orient faces */
4754   for (c = 0; c < numCells; ++c) {
4755     const PetscInt *cone, *cellFaces;
4756     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4757 
4758     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4759     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4760     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4761     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4762     if (coneSize != numCellFaces) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4763     for (cf = 0; cf < numCellFaces; ++cf) {
4764       PetscInt *origClosure = NULL, *closure;
4765       PetscInt closureSize, i;
4766 
4767       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4768       if (closureSize != 7) SETERRQ2(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4769       for (i = 4; i < 7; ++i) {
4770         if ((origClosure[i*2] < vStart) || (origClosure[i*2] >= vEnd)) SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Invalid closure point %D should be a vertex in [%D, %D)", origClosure[i*2], vStart, vEnd);
4771       }
4772       closure = &origClosure[4*2];
4773       /* Remember that this is the orientation for edges, not vertices */
4774       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4775         /* Correctly oriented */
4776         mesh->coneOrientations[coff+cf] = 0;
4777       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4778         /* Shifted by 1 */
4779         mesh->coneOrientations[coff+cf] = 1;
4780       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4781         /* Shifted by 2 */
4782         mesh->coneOrientations[coff+cf] = 2;
4783       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4784         /* Start at edge 1, and reverse orientation */
4785         mesh->coneOrientations[coff+cf] = -(1+1);
4786       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4787         /* Start at index 0, and reverse orientation */
4788         mesh->coneOrientations[coff+cf] = -(0+1);
4789       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4790         /* Start at index 2, and reverse orientation */
4791         mesh->coneOrientations[coff+cf] = -(2+1);
4792       } else SETERRQ3(PetscObjectComm((PetscObject)idm), PETSC_ERR_PLIB, "Face %D did not match local face %D in cell %D for any orientation", cone[cf], cf, c);
4793       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4794     }
4795   }
4796   {
4797     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4798     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4799     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4800   }
4801   *dmInt = idm;
4802   PetscFunctionReturn(0);
4803 }
4804 
4805 #undef __FUNCT__
4806 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4807 /*
4808   This takes as input the common mesh generator output, a list of the vertices for each cell
4809 */
4810 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4811 {
4812   PetscInt      *cone, c, p;
4813   PetscErrorCode ierr;
4814 
4815   PetscFunctionBegin;
4816   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4817   for (c = 0; c < numCells; ++c) {
4818     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4819   }
4820   ierr = DMSetUp(dm);CHKERRQ(ierr);
4821   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4822   for (c = 0; c < numCells; ++c) {
4823     for (p = 0; p < numCorners; ++p) {
4824       cone[p] = cells[c*numCorners+p]+numCells;
4825     }
4826     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4827   }
4828   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4829   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4830   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4831   PetscFunctionReturn(0);
4832 }
4833 
4834 #undef __FUNCT__
4835 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4836 /*
4837   This takes as input the coordinates for each vertex
4838 */
4839 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4840 {
4841   PetscSection   coordSection;
4842   Vec            coordinates;
4843   PetscScalar   *coords;
4844   PetscInt       coordSize, v, d;
4845   PetscErrorCode ierr;
4846 
4847   PetscFunctionBegin;
4848   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4849   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4850   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4851   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4852   for (v = numCells; v < numCells+numVertices; ++v) {
4853     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4854     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4855   }
4856   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4857   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4858   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4859   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4860   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4861   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4862   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4863   for (v = 0; v < numVertices; ++v) {
4864     for (d = 0; d < spaceDim; ++d) {
4865       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4866     }
4867   }
4868   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4869   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4870   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4871   PetscFunctionReturn(0);
4872 }
4873 
4874 #undef __FUNCT__
4875 #define __FUNCT__ "DMPlexCreateFromCellList"
4876 /*
4877   This takes as input the common mesh generator output, a list of the vertices for each cell
4878 */
4879 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4880 {
4881   PetscErrorCode ierr;
4882 
4883   PetscFunctionBegin;
4884   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4885   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4886   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4887   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4888   if (interpolate) {
4889     DM idm;
4890 
4891     switch (dim) {
4892     case 2:
4893       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4894     case 3:
4895       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4896     default:
4897       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4898     }
4899     ierr = DMDestroy(dm);CHKERRQ(ierr);
4900     *dm  = idm;
4901   }
4902   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4903   PetscFunctionReturn(0);
4904 }
4905 
4906 #undef __FUNCT__
4907 #define __FUNCT__ "DMPlexCreateFromDAG"
4908 /*
4909   This takes as input the raw Hasse Diagram data
4910 */
4911 PetscErrorCode DMPlexCreateFromDAG(DM dm, PetscInt depth, const PetscInt numPoints[], const PetscInt coneSize[], const PetscInt cones[], const PetscInt coneOrientations[], const PetscScalar vertexCoords[])
4912 {
4913   Vec            coordinates;
4914   PetscSection   coordSection;
4915   PetscScalar    *coords;
4916   PetscInt       coordSize, firstVertex = numPoints[depth], pStart = 0, pEnd = 0, p, v, dim, d, off;
4917   PetscErrorCode ierr;
4918 
4919   PetscFunctionBegin;
4920   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4921   for (d = 0; d <= depth; ++d) pEnd += numPoints[d];
4922   ierr = DMPlexSetChart(dm, pStart, pEnd);CHKERRQ(ierr);
4923   for (p = pStart; p < pEnd; ++p) {
4924     ierr = DMPlexSetConeSize(dm, p, coneSize[p-pStart]);CHKERRQ(ierr);
4925   }
4926   ierr = DMSetUp(dm);CHKERRQ(ierr); /* Allocate space for cones */
4927   for (p = pStart, off = 0; p < pEnd; off += coneSize[p-pStart], ++p) {
4928     ierr = DMPlexSetCone(dm, p, &cones[off]);CHKERRQ(ierr);
4929     ierr = DMPlexSetConeOrientation(dm, p, &coneOrientations[off]);CHKERRQ(ierr);
4930   }
4931   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4932   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4933   /* Build coordinates */
4934   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4935   ierr = PetscSectionSetChart(coordSection, firstVertex, firstVertex+numPoints[0]);CHKERRQ(ierr);
4936   for (v = firstVertex; v < firstVertex+numPoints[0]; ++v) {
4937     ierr = PetscSectionSetDof(coordSection, v, dim);CHKERRQ(ierr);
4938   }
4939   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4940   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4941   ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinates);CHKERRQ(ierr);
4942   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4943   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4944   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4945   for (v = 0; v < numPoints[0]; ++v) {
4946     PetscInt off;
4947 
4948     ierr = PetscSectionGetOffset(coordSection, v+firstVertex, &off);CHKERRQ(ierr);
4949     for (d = 0; d < dim; ++d) {
4950       coords[off+d] = vertexCoords[v*dim+d];
4951     }
4952   }
4953   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4954   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4955   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4956   PetscFunctionReturn(0);
4957 }
4958 
4959 #if defined(PETSC_HAVE_TRIANGLE)
4960 #include <triangle.h>
4961 
4962 #undef __FUNCT__
4963 #define __FUNCT__ "InitInput_Triangle"
4964 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4965 {
4966   PetscFunctionBegin;
4967   inputCtx->numberofpoints             = 0;
4968   inputCtx->numberofpointattributes    = 0;
4969   inputCtx->pointlist                  = NULL;
4970   inputCtx->pointattributelist         = NULL;
4971   inputCtx->pointmarkerlist            = NULL;
4972   inputCtx->numberofsegments           = 0;
4973   inputCtx->segmentlist                = NULL;
4974   inputCtx->segmentmarkerlist          = NULL;
4975   inputCtx->numberoftriangleattributes = 0;
4976   inputCtx->trianglelist               = NULL;
4977   inputCtx->numberofholes              = 0;
4978   inputCtx->holelist                   = NULL;
4979   inputCtx->numberofregions            = 0;
4980   inputCtx->regionlist                 = NULL;
4981   PetscFunctionReturn(0);
4982 }
4983 
4984 #undef __FUNCT__
4985 #define __FUNCT__ "InitOutput_Triangle"
4986 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4987 {
4988   PetscFunctionBegin;
4989   outputCtx->numberofpoints        = 0;
4990   outputCtx->pointlist             = NULL;
4991   outputCtx->pointattributelist    = NULL;
4992   outputCtx->pointmarkerlist       = NULL;
4993   outputCtx->numberoftriangles     = 0;
4994   outputCtx->trianglelist          = NULL;
4995   outputCtx->triangleattributelist = NULL;
4996   outputCtx->neighborlist          = NULL;
4997   outputCtx->segmentlist           = NULL;
4998   outputCtx->segmentmarkerlist     = NULL;
4999   outputCtx->numberofedges         = 0;
5000   outputCtx->edgelist              = NULL;
5001   outputCtx->edgemarkerlist        = NULL;
5002   PetscFunctionReturn(0);
5003 }
5004 
5005 #undef __FUNCT__
5006 #define __FUNCT__ "FiniOutput_Triangle"
5007 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
5008 {
5009   PetscFunctionBegin;
5010   free(outputCtx->pointmarkerlist);
5011   free(outputCtx->edgelist);
5012   free(outputCtx->edgemarkerlist);
5013   free(outputCtx->trianglelist);
5014   free(outputCtx->neighborlist);
5015   PetscFunctionReturn(0);
5016 }
5017 
5018 #undef __FUNCT__
5019 #define __FUNCT__ "DMPlexGenerate_Triangle"
5020 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
5021 {
5022   MPI_Comm             comm;
5023   PetscInt             dim              = 2;
5024   const PetscBool      createConvexHull = PETSC_FALSE;
5025   const PetscBool      constrained      = PETSC_FALSE;
5026   struct triangulateio in;
5027   struct triangulateio out;
5028   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
5029   PetscMPIInt          rank;
5030   PetscErrorCode       ierr;
5031 
5032   PetscFunctionBegin;
5033   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5034   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5035   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5036   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5037   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5038 
5039   in.numberofpoints = vEnd - vStart;
5040   if (in.numberofpoints > 0) {
5041     PetscSection coordSection;
5042     Vec          coordinates;
5043     PetscScalar *array;
5044 
5045     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5046     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5047     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5048     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5049     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5050     for (v = vStart; v < vEnd; ++v) {
5051       const PetscInt idx = v - vStart;
5052       PetscInt       off, d;
5053 
5054       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5055       for (d = 0; d < dim; ++d) {
5056         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5057       }
5058       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5059     }
5060     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5061   }
5062   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
5063   in.numberofsegments = eEnd - eStart;
5064   if (in.numberofsegments > 0) {
5065     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
5066     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
5067     for (e = eStart; e < eEnd; ++e) {
5068       const PetscInt  idx = e - eStart;
5069       const PetscInt *cone;
5070 
5071       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
5072 
5073       in.segmentlist[idx*2+0] = cone[0] - vStart;
5074       in.segmentlist[idx*2+1] = cone[1] - vStart;
5075 
5076       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5077     }
5078   }
5079 #if 0 /* Do not currently support holes */
5080   PetscReal *holeCoords;
5081   PetscInt   h, d;
5082 
5083   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5084   if (in.numberofholes > 0) {
5085     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5086     for (h = 0; h < in.numberofholes; ++h) {
5087       for (d = 0; d < dim; ++d) {
5088         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5089       }
5090     }
5091   }
5092 #endif
5093   if (!rank) {
5094     char args[32];
5095 
5096     /* Take away 'Q' for verbose output */
5097     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5098     if (createConvexHull) {
5099       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5100     }
5101     if (constrained) {
5102       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5103     }
5104     triangulate(args, &in, &out, NULL);
5105   }
5106   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5107   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5108   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5109   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5110   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5111 
5112   {
5113     const PetscInt numCorners  = 3;
5114     const PetscInt numCells    = out.numberoftriangles;
5115     const PetscInt numVertices = out.numberofpoints;
5116     const int     *cells      = out.trianglelist;
5117     const double  *meshCoords = out.pointlist;
5118 
5119     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5120     /* Set labels */
5121     for (v = 0; v < numVertices; ++v) {
5122       if (out.pointmarkerlist[v]) {
5123         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5124       }
5125     }
5126     if (interpolate) {
5127       for (e = 0; e < out.numberofedges; e++) {
5128         if (out.edgemarkerlist[e]) {
5129           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5130           const PetscInt *edges;
5131           PetscInt        numEdges;
5132 
5133           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5134           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5135           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5136           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5137         }
5138       }
5139     }
5140     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5141   }
5142 #if 0 /* Do not currently support holes */
5143   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5144 #endif
5145   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5146   PetscFunctionReturn(0);
5147 }
5148 
5149 #undef __FUNCT__
5150 #define __FUNCT__ "DMPlexRefine_Triangle"
5151 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5152 {
5153   MPI_Comm             comm;
5154   PetscInt             dim  = 2;
5155   struct triangulateio in;
5156   struct triangulateio out;
5157   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5158   PetscMPIInt          rank;
5159   PetscErrorCode       ierr;
5160 
5161   PetscFunctionBegin;
5162   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5163   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5164   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5165   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5166   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5167   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5168   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5169 
5170   in.numberofpoints = vEnd - vStart;
5171   if (in.numberofpoints > 0) {
5172     PetscSection coordSection;
5173     Vec          coordinates;
5174     PetscScalar *array;
5175 
5176     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5177     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5178     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5179     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5180     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5181     for (v = vStart; v < vEnd; ++v) {
5182       const PetscInt idx = v - vStart;
5183       PetscInt       off, d;
5184 
5185       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5186       for (d = 0; d < dim; ++d) {
5187         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5188       }
5189       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5190     }
5191     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5192   }
5193   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5194 
5195   in.numberofcorners   = 3;
5196   in.numberoftriangles = cEnd - cStart;
5197 
5198   in.trianglearealist  = (double*) maxVolumes;
5199   if (in.numberoftriangles > 0) {
5200     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5201     for (c = cStart; c < cEnd; ++c) {
5202       const PetscInt idx      = c - cStart;
5203       PetscInt      *closure = NULL;
5204       PetscInt       closureSize;
5205 
5206       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5207       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5208       for (v = 0; v < 3; ++v) {
5209         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5210       }
5211       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5212     }
5213   }
5214   /* TODO: Segment markers are missing on input */
5215 #if 0 /* Do not currently support holes */
5216   PetscReal *holeCoords;
5217   PetscInt   h, d;
5218 
5219   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5220   if (in.numberofholes > 0) {
5221     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5222     for (h = 0; h < in.numberofholes; ++h) {
5223       for (d = 0; d < dim; ++d) {
5224         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5225       }
5226     }
5227   }
5228 #endif
5229   if (!rank) {
5230     char args[32];
5231 
5232     /* Take away 'Q' for verbose output */
5233     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5234     triangulate(args, &in, &out, NULL);
5235   }
5236   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5237   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5238   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5239   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5240   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5241 
5242   {
5243     const PetscInt numCorners  = 3;
5244     const PetscInt numCells    = out.numberoftriangles;
5245     const PetscInt numVertices = out.numberofpoints;
5246     const int     *cells      = out.trianglelist;
5247     const double  *meshCoords = out.pointlist;
5248     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5249 
5250     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5251     /* Set labels */
5252     for (v = 0; v < numVertices; ++v) {
5253       if (out.pointmarkerlist[v]) {
5254         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5255       }
5256     }
5257     if (interpolate) {
5258       PetscInt e;
5259 
5260       for (e = 0; e < out.numberofedges; e++) {
5261         if (out.edgemarkerlist[e]) {
5262           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5263           const PetscInt *edges;
5264           PetscInt        numEdges;
5265 
5266           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5267           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5268           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5269           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5270         }
5271       }
5272     }
5273     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5274   }
5275 #if 0 /* Do not currently support holes */
5276   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5277 #endif
5278   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5279   PetscFunctionReturn(0);
5280 }
5281 #endif
5282 
5283 #if defined(PETSC_HAVE_TETGEN)
5284 #include <tetgen.h>
5285 #undef __FUNCT__
5286 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5287 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5288 {
5289   MPI_Comm       comm;
5290   const PetscInt dim  = 3;
5291   ::tetgenio     in;
5292   ::tetgenio     out;
5293   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5294   PetscMPIInt    rank;
5295   PetscErrorCode ierr;
5296 
5297   PetscFunctionBegin;
5298   ierr              = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5299   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5300   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5301   in.numberofpoints = vEnd - vStart;
5302   if (in.numberofpoints > 0) {
5303     PetscSection coordSection;
5304     Vec          coordinates;
5305     PetscScalar *array;
5306 
5307     in.pointlist       = new double[in.numberofpoints*dim];
5308     in.pointmarkerlist = new int[in.numberofpoints];
5309 
5310     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5311     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5312     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5313     for (v = vStart; v < vEnd; ++v) {
5314       const PetscInt idx = v - vStart;
5315       PetscInt       off, d;
5316 
5317       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5318       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5319       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5320     }
5321     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5322   }
5323   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5324 
5325   in.numberoffacets = fEnd - fStart;
5326   if (in.numberoffacets > 0) {
5327     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5328     in.facetmarkerlist = new int[in.numberoffacets];
5329     for (f = fStart; f < fEnd; ++f) {
5330       const PetscInt idx     = f - fStart;
5331       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v;
5332 
5333       in.facetlist[idx].numberofpolygons = 1;
5334       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5335       in.facetlist[idx].numberofholes    = 0;
5336       in.facetlist[idx].holelist         = NULL;
5337 
5338       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5339       for (p = 0; p < numPoints*2; p += 2) {
5340         const PetscInt point = points[p];
5341         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5342       }
5343 
5344       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5345       poly->numberofvertices = numVertices;
5346       poly->vertexlist       = new int[poly->numberofvertices];
5347       for (v = 0; v < numVertices; ++v) {
5348         const PetscInt vIdx = points[v] - vStart;
5349         poly->vertexlist[v] = vIdx;
5350       }
5351       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5352       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5353     }
5354   }
5355   if (!rank) {
5356     char args[32];
5357 
5358     /* Take away 'Q' for verbose output */
5359     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5360     ::tetrahedralize(args, &in, &out);
5361   }
5362   {
5363     const PetscInt numCorners  = 4;
5364     const PetscInt numCells    = out.numberoftetrahedra;
5365     const PetscInt numVertices = out.numberofpoints;
5366     const int     *cells      = out.tetrahedronlist;
5367     const double  *meshCoords = out.pointlist;
5368 
5369     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5370     /* Set labels */
5371     for (v = 0; v < numVertices; ++v) {
5372       if (out.pointmarkerlist[v]) {
5373         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5374       }
5375     }
5376     if (interpolate) {
5377       PetscInt e;
5378 
5379       for (e = 0; e < out.numberofedges; e++) {
5380         if (out.edgemarkerlist[e]) {
5381           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5382           const PetscInt *edges;
5383           PetscInt        numEdges;
5384 
5385           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5386           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5387           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5388           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5389         }
5390       }
5391       for (f = 0; f < out.numberoftrifaces; f++) {
5392         if (out.trifacemarkerlist[f]) {
5393           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5394           const PetscInt *faces;
5395           PetscInt        numFaces;
5396 
5397           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5398           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5399           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5400           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5401         }
5402       }
5403     }
5404     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5405   }
5406   PetscFunctionReturn(0);
5407 }
5408 
5409 #undef __FUNCT__
5410 #define __FUNCT__ "DMPlexRefine_Tetgen"
5411 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5412 {
5413   MPI_Comm       comm;
5414   const PetscInt dim  = 3;
5415   ::tetgenio     in;
5416   ::tetgenio     out;
5417   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5418   PetscMPIInt    rank;
5419   PetscErrorCode ierr;
5420 
5421   PetscFunctionBegin;
5422   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5423   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5424   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5425   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5426   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5427 
5428   in.numberofpoints = vEnd - vStart;
5429   if (in.numberofpoints > 0) {
5430     PetscSection coordSection;
5431     Vec          coordinates;
5432     PetscScalar *array;
5433 
5434     in.pointlist       = new double[in.numberofpoints*dim];
5435     in.pointmarkerlist = new int[in.numberofpoints];
5436 
5437     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5438     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5439     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5440     for (v = vStart; v < vEnd; ++v) {
5441       const PetscInt idx = v - vStart;
5442       PetscInt       off, d;
5443 
5444       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5445       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5446       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5447     }
5448     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5449   }
5450   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5451 
5452   in.numberofcorners       = 4;
5453   in.numberoftetrahedra    = cEnd - cStart;
5454   in.tetrahedronvolumelist = (double*) maxVolumes;
5455   if (in.numberoftetrahedra > 0) {
5456     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5457     for (c = cStart; c < cEnd; ++c) {
5458       const PetscInt idx      = c - cStart;
5459       PetscInt      *closure = NULL;
5460       PetscInt       closureSize;
5461 
5462       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5463       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5464       for (v = 0; v < 4; ++v) {
5465         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5466       }
5467       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5468     }
5469   }
5470   /* TODO: Put in boundary faces with markers */
5471   if (!rank) {
5472     char args[32];
5473 
5474     /* Take away 'Q' for verbose output */
5475     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5476     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5477     ::tetrahedralize(args, &in, &out);
5478   }
5479   in.tetrahedronvolumelist = NULL;
5480 
5481   {
5482     const PetscInt numCorners  = 4;
5483     const PetscInt numCells    = out.numberoftetrahedra;
5484     const PetscInt numVertices = out.numberofpoints;
5485     const int     *cells      = out.tetrahedronlist;
5486     const double  *meshCoords = out.pointlist;
5487     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5488 
5489     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5490     /* Set labels */
5491     for (v = 0; v < numVertices; ++v) {
5492       if (out.pointmarkerlist[v]) {
5493         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5494       }
5495     }
5496     if (interpolate) {
5497       PetscInt e, f;
5498 
5499       for (e = 0; e < out.numberofedges; e++) {
5500         if (out.edgemarkerlist[e]) {
5501           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5502           const PetscInt *edges;
5503           PetscInt        numEdges;
5504 
5505           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5506           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5507           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5508           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5509         }
5510       }
5511       for (f = 0; f < out.numberoftrifaces; f++) {
5512         if (out.trifacemarkerlist[f]) {
5513           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5514           const PetscInt *faces;
5515           PetscInt        numFaces;
5516 
5517           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5518           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5519           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5520           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5521         }
5522       }
5523     }
5524     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5525   }
5526   PetscFunctionReturn(0);
5527 }
5528 #endif
5529 
5530 #if defined(PETSC_HAVE_CTETGEN)
5531 #include "ctetgen.h"
5532 
5533 #undef __FUNCT__
5534 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5535 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5536 {
5537   MPI_Comm       comm;
5538   const PetscInt dim  = 3;
5539   PLC           *in, *out;
5540   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5541   PetscMPIInt    rank;
5542   PetscErrorCode ierr;
5543 
5544   PetscFunctionBegin;
5545   ierr = PetscObjectGetComm((PetscObject)boundary,&comm);CHKERRQ(ierr);
5546   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5547   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5548   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5549   ierr = PLCCreate(&in);CHKERRQ(ierr);
5550   ierr = PLCCreate(&out);CHKERRQ(ierr);
5551 
5552   in->numberofpoints = vEnd - vStart;
5553   if (in->numberofpoints > 0) {
5554     PetscSection coordSection;
5555     Vec          coordinates;
5556     PetscScalar *array;
5557 
5558     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5559     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5560     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5561     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5562     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5563     for (v = vStart; v < vEnd; ++v) {
5564       const PetscInt idx = v - vStart;
5565       PetscInt       off, d, m;
5566 
5567       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5568       for (d = 0; d < dim; ++d) {
5569         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5570       }
5571       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5572 
5573       in->pointmarkerlist[idx] = (int) m;
5574     }
5575     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5576   }
5577   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5578 
5579   in->numberoffacets = fEnd - fStart;
5580   if (in->numberoffacets > 0) {
5581     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5582     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5583     for (f = fStart; f < fEnd; ++f) {
5584       const PetscInt idx     = f - fStart;
5585       PetscInt      *points = NULL, numPoints, p, numVertices = 0, v, m;
5586       polygon       *poly;
5587 
5588       in->facetlist[idx].numberofpolygons = 1;
5589 
5590       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5591 
5592       in->facetlist[idx].numberofholes    = 0;
5593       in->facetlist[idx].holelist         = NULL;
5594 
5595       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5596       for (p = 0; p < numPoints*2; p += 2) {
5597         const PetscInt point = points[p];
5598         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5599       }
5600 
5601       poly                   = in->facetlist[idx].polygonlist;
5602       poly->numberofvertices = numVertices;
5603       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5604       for (v = 0; v < numVertices; ++v) {
5605         const PetscInt vIdx = points[v] - vStart;
5606         poly->vertexlist[v] = vIdx;
5607       }
5608       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5609       in->facetmarkerlist[idx] = (int) m;
5610       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5611     }
5612   }
5613   if (!rank) {
5614     TetGenOpts t;
5615 
5616     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5617     t.in        = boundary; /* Should go away */
5618     t.plc       = 1;
5619     t.quality   = 1;
5620     t.edgesout  = 1;
5621     t.zeroindex = 1;
5622     t.quiet     = 1;
5623     t.verbose   = verbose;
5624     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5625     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5626   }
5627   {
5628     const PetscInt numCorners  = 4;
5629     const PetscInt numCells    = out->numberoftetrahedra;
5630     const PetscInt numVertices = out->numberofpoints;
5631     const int     *cells      = out->tetrahedronlist;
5632     const double  *meshCoords = out->pointlist;
5633 
5634     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5635     /* Set labels */
5636     for (v = 0; v < numVertices; ++v) {
5637       if (out->pointmarkerlist[v]) {
5638         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5639       }
5640     }
5641     if (interpolate) {
5642       PetscInt e;
5643 
5644       for (e = 0; e < out->numberofedges; e++) {
5645         if (out->edgemarkerlist[e]) {
5646           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5647           const PetscInt *edges;
5648           PetscInt        numEdges;
5649 
5650           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5651           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5652           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5653           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5654         }
5655       }
5656       for (f = 0; f < out->numberoftrifaces; f++) {
5657         if (out->trifacemarkerlist[f]) {
5658           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5659           const PetscInt *faces;
5660           PetscInt        numFaces;
5661 
5662           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5663           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5664           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5665           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5666         }
5667       }
5668     }
5669     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5670   }
5671 
5672   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5673   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5674   PetscFunctionReturn(0);
5675 }
5676 
5677 #undef __FUNCT__
5678 #define __FUNCT__ "DMPlexRefine_CTetgen"
5679 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5680 {
5681   MPI_Comm       comm;
5682   const PetscInt dim  = 3;
5683   PLC           *in, *out;
5684   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5685   PetscMPIInt    rank;
5686   PetscErrorCode ierr;
5687 
5688   PetscFunctionBegin;
5689   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
5690   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, NULL);CHKERRQ(ierr);
5691   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5692   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5693   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5694   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5695   ierr = PLCCreate(&in);CHKERRQ(ierr);
5696   ierr = PLCCreate(&out);CHKERRQ(ierr);
5697 
5698   in->numberofpoints = vEnd - vStart;
5699   if (in->numberofpoints > 0) {
5700     PetscSection coordSection;
5701     Vec          coordinates;
5702     PetscScalar *array;
5703 
5704     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5705     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5706     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5707     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5708     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5709     for (v = vStart; v < vEnd; ++v) {
5710       const PetscInt idx = v - vStart;
5711       PetscInt       off, d, m;
5712 
5713       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5714       for (d = 0; d < dim; ++d) {
5715         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5716       }
5717       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5718 
5719       in->pointmarkerlist[idx] = (int) m;
5720     }
5721     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5722   }
5723   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5724 
5725   in->numberofcorners       = 4;
5726   in->numberoftetrahedra    = cEnd - cStart;
5727   in->tetrahedronvolumelist = maxVolumes;
5728   if (in->numberoftetrahedra > 0) {
5729     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5730     for (c = cStart; c < cEnd; ++c) {
5731       const PetscInt idx      = c - cStart;
5732       PetscInt      *closure = NULL;
5733       PetscInt       closureSize;
5734 
5735       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5736       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5737       for (v = 0; v < 4; ++v) {
5738         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5739       }
5740       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5741     }
5742   }
5743   if (!rank) {
5744     TetGenOpts t;
5745 
5746     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5747 
5748     t.in        = dm; /* Should go away */
5749     t.refine    = 1;
5750     t.varvolume = 1;
5751     t.quality   = 1;
5752     t.edgesout  = 1;
5753     t.zeroindex = 1;
5754     t.quiet     = 1;
5755     t.verbose   = verbose; /* Change this */
5756 
5757     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5758     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5759   }
5760   {
5761     const PetscInt numCorners  = 4;
5762     const PetscInt numCells    = out->numberoftetrahedra;
5763     const PetscInt numVertices = out->numberofpoints;
5764     const int     *cells       = out->tetrahedronlist;
5765     const double  *meshCoords  = out->pointlist;
5766     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5767 
5768     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5769     /* Set labels */
5770     for (v = 0; v < numVertices; ++v) {
5771       if (out->pointmarkerlist[v]) {
5772         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5773       }
5774     }
5775     if (interpolate) {
5776       PetscInt e, f;
5777 
5778       for (e = 0; e < out->numberofedges; e++) {
5779         if (out->edgemarkerlist[e]) {
5780           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5781           const PetscInt *edges;
5782           PetscInt        numEdges;
5783 
5784           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5785           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5786           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5787           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5788         }
5789       }
5790       for (f = 0; f < out->numberoftrifaces; f++) {
5791         if (out->trifacemarkerlist[f]) {
5792           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5793           const PetscInt *faces;
5794           PetscInt        numFaces;
5795 
5796           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5797           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5798           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5799           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5800         }
5801       }
5802     }
5803     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5804   }
5805   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5806   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5807   PetscFunctionReturn(0);
5808 }
5809 #endif
5810 
5811 #undef __FUNCT__
5812 #define __FUNCT__ "DMPlexGenerate"
5813 /*@C
5814   DMPlexGenerate - Generates a mesh.
5815 
5816   Not Collective
5817 
5818   Input Parameters:
5819 + boundary - The DMPlex boundary object
5820 . name - The mesh generation package name
5821 - interpolate - Flag to create intermediate mesh elements
5822 
5823   Output Parameter:
5824 . mesh - The DMPlex object
5825 
5826   Level: intermediate
5827 
5828 .keywords: mesh, elements
5829 .seealso: DMPlexCreate(), DMRefine()
5830 @*/
5831 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5832 {
5833   PetscInt       dim;
5834   char           genname[1024];
5835   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5836   PetscErrorCode ierr;
5837 
5838   PetscFunctionBegin;
5839   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5840   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5841   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5842   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5843   if (flg) name = genname;
5844   if (name) {
5845     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5846     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5847     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5848   }
5849   switch (dim) {
5850   case 1:
5851     if (!name || isTriangle) {
5852 #if defined(PETSC_HAVE_TRIANGLE)
5853       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5854 #else
5855       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5856 #endif
5857     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5858     break;
5859   case 2:
5860     if (!name || isCTetgen) {
5861 #if defined(PETSC_HAVE_CTETGEN)
5862       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5863 #else
5864       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5865 #endif
5866     } else if (isTetgen) {
5867 #if defined(PETSC_HAVE_TETGEN)
5868       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5869 #else
5870       SETERRQ(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5871 #endif
5872     } else SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5873     break;
5874   default:
5875     SETERRQ1(PetscObjectComm((PetscObject)boundary), PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5876   }
5877   PetscFunctionReturn(0);
5878 }
5879 
5880 typedef PetscInt CellRefiner;
5881 
5882 #undef __FUNCT__
5883 #define __FUNCT__ "GetDepthStart_Private"
5884 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5885 {
5886   PetscFunctionBegin;
5887   if (cStart) *cStart = 0;
5888   if (vStart) *vStart = depthSize[depth];
5889   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5890   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5891   PetscFunctionReturn(0);
5892 }
5893 
5894 #undef __FUNCT__
5895 #define __FUNCT__ "GetDepthEnd_Private"
5896 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5897 {
5898   PetscFunctionBegin;
5899   if (cEnd) *cEnd = depthSize[depth];
5900   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5901   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5902   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5903   PetscFunctionReturn(0);
5904 }
5905 
5906 #undef __FUNCT__
5907 #define __FUNCT__ "CellRefinerGetSizes"
5908 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5909 {
5910   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5911   PetscErrorCode ierr;
5912 
5913   PetscFunctionBegin;
5914   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5915   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5916   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5917   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5918   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5919   switch (refiner) {
5920   case 1:
5921     /* Simplicial 2D */
5922     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5923     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5924     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5925     break;
5926   case 3:
5927     /* Hybrid 2D */
5928     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5929     cMax = PetscMin(cEnd, cMax);
5930     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5931     fMax         = PetscMin(fEnd, fMax);
5932     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5933     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 */
5934     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5935     break;
5936   case 2:
5937     /* Hex 2D */
5938     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5939     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5940     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5941     break;
5942   default:
5943     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5944   }
5945   PetscFunctionReturn(0);
5946 }
5947 
5948 #undef __FUNCT__
5949 #define __FUNCT__ "CellRefinerSetConeSizes"
5950 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5951 {
5952   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5953   PetscErrorCode ierr;
5954 
5955   PetscFunctionBegin;
5956   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5957   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5958   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5959   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5960   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5961   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5962   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5963   switch (refiner) {
5964   case 1:
5965     /* Simplicial 2D */
5966     /* All cells have 3 faces */
5967     for (c = cStart; c < cEnd; ++c) {
5968       for (r = 0; r < 4; ++r) {
5969         const PetscInt newp = (c - cStart)*4 + r;
5970 
5971         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5972       }
5973     }
5974     /* Split faces have 2 vertices and the same cells as the parent */
5975     for (f = fStart; f < fEnd; ++f) {
5976       for (r = 0; r < 2; ++r) {
5977         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5978         PetscInt       size;
5979 
5980         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5981         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5982         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5983       }
5984     }
5985     /* Interior faces have 2 vertices and 2 cells */
5986     for (c = cStart; c < cEnd; ++c) {
5987       for (r = 0; r < 3; ++r) {
5988         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5989 
5990         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5991         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5992       }
5993     }
5994     /* Old vertices have identical supports */
5995     for (v = vStart; v < vEnd; ++v) {
5996       const PetscInt newp = vStartNew + (v - vStart);
5997       PetscInt       size;
5998 
5999       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6000       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6001     }
6002     /* Face vertices have 2 + cells*2 supports */
6003     for (f = fStart; f < fEnd; ++f) {
6004       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6005       PetscInt       size;
6006 
6007       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6008       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
6009     }
6010     break;
6011   case 2:
6012     /* Hex 2D */
6013     /* All cells have 4 faces */
6014     for (c = cStart; c < cEnd; ++c) {
6015       for (r = 0; r < 4; ++r) {
6016         const PetscInt newp = (c - cStart)*4 + r;
6017 
6018         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6019       }
6020     }
6021     /* Split faces have 2 vertices and the same cells as the parent */
6022     for (f = fStart; f < fEnd; ++f) {
6023       for (r = 0; r < 2; ++r) {
6024         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6025         PetscInt       size;
6026 
6027         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6028         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6029         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6030       }
6031     }
6032     /* Interior faces have 2 vertices and 2 cells */
6033     for (c = cStart; c < cEnd; ++c) {
6034       for (r = 0; r < 4; ++r) {
6035         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6036 
6037         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6038         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6039       }
6040     }
6041     /* Old vertices have identical supports */
6042     for (v = vStart; v < vEnd; ++v) {
6043       const PetscInt newp = vStartNew + (v - vStart);
6044       PetscInt       size;
6045 
6046       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6047       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6048     }
6049     /* Face vertices have 2 + cells supports */
6050     for (f = fStart; f < fEnd; ++f) {
6051       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6052       PetscInt       size;
6053 
6054       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6055       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
6056     }
6057     /* Cell vertices have 4 supports */
6058     for (c = cStart; c < cEnd; ++c) {
6059       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6060 
6061       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
6062     }
6063     break;
6064   case 3:
6065     /* Hybrid 2D */
6066     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6067     cMax = PetscMin(cEnd, cMax);
6068     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6069     fMax = PetscMin(fEnd, fMax);
6070     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6071     /* Interior cells have 3 faces */
6072     for (c = cStart; c < cMax; ++c) {
6073       for (r = 0; r < 4; ++r) {
6074         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
6075 
6076         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
6077       }
6078     }
6079     /* Hybrid cells have 4 faces */
6080     for (c = cMax; c < cEnd; ++c) {
6081       for (r = 0; r < 2; ++r) {
6082         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6083 
6084         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6085       }
6086     }
6087     /* Interior split faces have 2 vertices and the same cells as the parent */
6088     for (f = fStart; f < fMax; ++f) {
6089       for (r = 0; r < 2; ++r) {
6090         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6091         PetscInt       size;
6092 
6093         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6094         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6095         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6096       }
6097     }
6098     /* Interior cell faces have 2 vertices and 2 cells */
6099     for (c = cStart; c < cMax; ++c) {
6100       for (r = 0; r < 3; ++r) {
6101         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6102 
6103         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6104         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6105       }
6106     }
6107     /* Hybrid faces have 2 vertices and the same cells */
6108     for (f = fMax; f < fEnd; ++f) {
6109       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6110       PetscInt       size;
6111 
6112       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6113       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6114       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6115     }
6116     /* Hybrid cell faces have 2 vertices and 2 cells */
6117     for (c = cMax; c < cEnd; ++c) {
6118       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6119 
6120       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6121       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6122     }
6123     /* Old vertices have identical supports */
6124     for (v = vStart; v < vEnd; ++v) {
6125       const PetscInt newp = vStartNew + (v - vStart);
6126       PetscInt       size;
6127 
6128       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6129       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6130     }
6131     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6132     for (f = fStart; f < fMax; ++f) {
6133       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6134       const PetscInt *support;
6135       PetscInt       size, newSize = 2, s;
6136 
6137       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6138       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6139       for (s = 0; s < size; ++s) {
6140         if (support[s] >= cMax) newSize += 1;
6141         else newSize += 2;
6142       }
6143       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6144     }
6145     break;
6146   default:
6147     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6148   }
6149   PetscFunctionReturn(0);
6150 }
6151 
6152 #undef __FUNCT__
6153 #define __FUNCT__ "CellRefinerSetCones"
6154 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6155 {
6156   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;
6157   PetscInt       maxSupportSize, *supportRef;
6158   PetscErrorCode ierr;
6159 
6160   PetscFunctionBegin;
6161   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6162   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6163   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6164   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6165   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6166   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6167   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6168   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6169   switch (refiner) {
6170   case 1:
6171     /* Simplicial 2D */
6172     /*
6173      2
6174      |\
6175      | \
6176      |  \
6177      |   \
6178      | C  \
6179      |     \
6180      |      \
6181      2---1---1
6182      |\  D  / \
6183      | 2   0   \
6184      |A \ /  B  \
6185      0---0-------1
6186      */
6187     /* All cells have 3 faces */
6188     for (c = cStart; c < cEnd; ++c) {
6189       const PetscInt  newp = cStartNew + (c - cStart)*4;
6190       const PetscInt *cone, *ornt;
6191       PetscInt        coneNew[3], orntNew[3];
6192 
6193       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6194       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6195       /* A triangle */
6196       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6197       orntNew[0] = ornt[0];
6198       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6199       orntNew[1] = -2;
6200       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6201       orntNew[2] = ornt[2];
6202       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6203       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6204 #if 1
6205       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);
6206       for (p = 0; p < 3; ++p) {
6207         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);
6208       }
6209 #endif
6210       /* B triangle */
6211       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6212       orntNew[0] = ornt[0];
6213       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6214       orntNew[1] = ornt[1];
6215       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6216       orntNew[2] = -2;
6217       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6218       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6219 #if 1
6220       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);
6221       for (p = 0; p < 3; ++p) {
6222         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);
6223       }
6224 #endif
6225       /* C triangle */
6226       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6227       orntNew[0] = -2;
6228       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6229       orntNew[1] = ornt[1];
6230       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6231       orntNew[2] = ornt[2];
6232       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6233       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6234 #if 1
6235       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);
6236       for (p = 0; p < 3; ++p) {
6237         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);
6238       }
6239 #endif
6240       /* D triangle */
6241       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6242       orntNew[0] = 0;
6243       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6244       orntNew[1] = 0;
6245       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6246       orntNew[2] = 0;
6247       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6248       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6249 #if 1
6250       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);
6251       for (p = 0; p < 3; ++p) {
6252         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);
6253       }
6254 #endif
6255     }
6256     /* Split faces have 2 vertices and the same cells as the parent */
6257     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6258     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6259     for (f = fStart; f < fEnd; ++f) {
6260       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6261 
6262       for (r = 0; r < 2; ++r) {
6263         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6264         const PetscInt *cone, *support;
6265         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6266 
6267         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6268         coneNew[0]       = vStartNew + (cone[0] - vStart);
6269         coneNew[1]       = vStartNew + (cone[1] - vStart);
6270         coneNew[(r+1)%2] = newv;
6271         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6272 #if 1
6273         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6274         for (p = 0; p < 2; ++p) {
6275           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);
6276         }
6277 #endif
6278         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6279         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6280         for (s = 0; s < supportSize; ++s) {
6281           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6282           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6283           for (c = 0; c < coneSize; ++c) {
6284             if (cone[c] == f) break;
6285           }
6286           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6287         }
6288         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6289 #if 1
6290         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6291         for (p = 0; p < supportSize; ++p) {
6292           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);
6293         }
6294 #endif
6295       }
6296     }
6297     /* Interior faces have 2 vertices and 2 cells */
6298     for (c = cStart; c < cEnd; ++c) {
6299       const PetscInt *cone;
6300 
6301       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6302       for (r = 0; r < 3; ++r) {
6303         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6304         PetscInt       coneNew[2];
6305         PetscInt       supportNew[2];
6306 
6307         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6308         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6309         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6310 #if 1
6311         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6312         for (p = 0; p < 2; ++p) {
6313           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);
6314         }
6315 #endif
6316         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6317         supportNew[1] = (c - cStart)*4 + 3;
6318         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6319 #if 1
6320         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6321         for (p = 0; p < 2; ++p) {
6322           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);
6323         }
6324 #endif
6325       }
6326     }
6327     /* Old vertices have identical supports */
6328     for (v = vStart; v < vEnd; ++v) {
6329       const PetscInt  newp = vStartNew + (v - vStart);
6330       const PetscInt *support, *cone;
6331       PetscInt        size, s;
6332 
6333       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6334       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6335       for (s = 0; s < size; ++s) {
6336         PetscInt r = 0;
6337 
6338         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6339         if (cone[1] == v) r = 1;
6340         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6341       }
6342       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6343 #if 1
6344       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6345       for (p = 0; p < size; ++p) {
6346         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);
6347       }
6348 #endif
6349     }
6350     /* Face vertices have 2 + cells*2 supports */
6351     for (f = fStart; f < fEnd; ++f) {
6352       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6353       const PetscInt *cone, *support;
6354       PetscInt        size, s;
6355 
6356       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6357       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6358       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6359       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6360       for (s = 0; s < size; ++s) {
6361         PetscInt r = 0;
6362 
6363         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6364         if      (cone[1] == f) r = 1;
6365         else if (cone[2] == f) r = 2;
6366         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6367         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6368       }
6369       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6370 #if 1
6371       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6372       for (p = 0; p < 2+size*2; ++p) {
6373         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);
6374       }
6375 #endif
6376     }
6377     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6378     break;
6379   case 2:
6380     /* Hex 2D */
6381     /*
6382      3---------2---------2
6383      |         |         |
6384      |    D    2    C    |
6385      |         |         |
6386      3----3----0----1----1
6387      |         |         |
6388      |    A    0    B    |
6389      |         |         |
6390      0---------0---------1
6391      */
6392     /* All cells have 4 faces */
6393     for (c = cStart; c < cEnd; ++c) {
6394       const PetscInt  newp = (c - cStart)*4;
6395       const PetscInt *cone, *ornt;
6396       PetscInt        coneNew[4], orntNew[4];
6397 
6398       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6399       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6400       /* A quad */
6401       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6402       orntNew[0] = ornt[0];
6403       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6404       orntNew[1] = 0;
6405       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6406       orntNew[2] = -2;
6407       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6408       orntNew[3] = ornt[3];
6409       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6410       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6411 #if 1
6412       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);
6413       for (p = 0; p < 4; ++p) {
6414         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);
6415       }
6416 #endif
6417       /* B quad */
6418       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6419       orntNew[0] = ornt[0];
6420       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6421       orntNew[1] = ornt[1];
6422       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6423       orntNew[2] = 0;
6424       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6425       orntNew[3] = -2;
6426       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6427       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6428 #if 1
6429       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);
6430       for (p = 0; p < 4; ++p) {
6431         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);
6432       }
6433 #endif
6434       /* C quad */
6435       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6436       orntNew[0] = -2;
6437       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6438       orntNew[1] = ornt[1];
6439       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6440       orntNew[2] = ornt[2];
6441       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6442       orntNew[3] = 0;
6443       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6444       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6445 #if 1
6446       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);
6447       for (p = 0; p < 4; ++p) {
6448         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);
6449       }
6450 #endif
6451       /* D quad */
6452       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6453       orntNew[0] = 0;
6454       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6455       orntNew[1] = -2;
6456       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6457       orntNew[2] = ornt[2];
6458       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6459       orntNew[3] = ornt[3];
6460       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6461       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6462 #if 1
6463       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);
6464       for (p = 0; p < 4; ++p) {
6465         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);
6466       }
6467 #endif
6468     }
6469     /* Split faces have 2 vertices and the same cells as the parent */
6470     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6471     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6472     for (f = fStart; f < fEnd; ++f) {
6473       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6474 
6475       for (r = 0; r < 2; ++r) {
6476         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6477         const PetscInt *cone, *support;
6478         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6479 
6480         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6481         coneNew[0]       = vStartNew + (cone[0] - vStart);
6482         coneNew[1]       = vStartNew + (cone[1] - vStart);
6483         coneNew[(r+1)%2] = newv;
6484         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6485 #if 1
6486         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6487         for (p = 0; p < 2; ++p) {
6488           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);
6489         }
6490 #endif
6491         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6492         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6493         for (s = 0; s < supportSize; ++s) {
6494           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6495           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6496           for (c = 0; c < coneSize; ++c) {
6497             if (cone[c] == f) break;
6498           }
6499           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6500         }
6501         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6502 #if 1
6503         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6504         for (p = 0; p < supportSize; ++p) {
6505           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);
6506         }
6507 #endif
6508       }
6509     }
6510     /* Interior faces have 2 vertices and 2 cells */
6511     for (c = cStart; c < cEnd; ++c) {
6512       const PetscInt *cone;
6513       PetscInt        coneNew[2], supportNew[2];
6514 
6515       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6516       for (r = 0; r < 4; ++r) {
6517         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6518 
6519         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6520         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6521         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6522 #if 1
6523         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6524         for (p = 0; p < 2; ++p) {
6525           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);
6526         }
6527 #endif
6528         supportNew[0] = (c - cStart)*4 + r;
6529         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6530         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6531 #if 1
6532         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6533         for (p = 0; p < 2; ++p) {
6534           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);
6535         }
6536 #endif
6537       }
6538     }
6539     /* Old vertices have identical supports */
6540     for (v = vStart; v < vEnd; ++v) {
6541       const PetscInt  newp = vStartNew + (v - vStart);
6542       const PetscInt *support, *cone;
6543       PetscInt        size, s;
6544 
6545       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6546       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6547       for (s = 0; s < size; ++s) {
6548         PetscInt r = 0;
6549 
6550         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6551         if (cone[1] == v) r = 1;
6552         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6553       }
6554       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6555 #if 1
6556       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6557       for (p = 0; p < size; ++p) {
6558         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);
6559       }
6560 #endif
6561     }
6562     /* Face vertices have 2 + cells supports */
6563     for (f = fStart; f < fEnd; ++f) {
6564       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6565       const PetscInt *cone, *support;
6566       PetscInt        size, s;
6567 
6568       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6569       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6570       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6571       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6572       for (s = 0; s < size; ++s) {
6573         PetscInt r = 0;
6574 
6575         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6576         if      (cone[1] == f) r = 1;
6577         else if (cone[2] == f) r = 2;
6578         else if (cone[3] == f) r = 3;
6579         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6580       }
6581       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6582 #if 1
6583       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6584       for (p = 0; p < 2+size; ++p) {
6585         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);
6586       }
6587 #endif
6588     }
6589     /* Cell vertices have 4 supports */
6590     for (c = cStart; c < cEnd; ++c) {
6591       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6592       PetscInt       supportNew[4];
6593 
6594       for (r = 0; r < 4; ++r) {
6595         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6596       }
6597       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6598     }
6599     break;
6600   case 3:
6601     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6602     cMax = PetscMin(cEnd, cMax);
6603     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6604     fMax = PetscMin(fEnd, fMax);
6605     /* Interior cells have 3 faces */
6606     for (c = cStart; c < cMax; ++c) {
6607       const PetscInt  newp = cStartNew + (c - cStart)*4;
6608       const PetscInt *cone, *ornt;
6609       PetscInt        coneNew[3], orntNew[3];
6610 
6611       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6612       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6613       /* A triangle */
6614       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6615       orntNew[0] = ornt[0];
6616       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6617       orntNew[1] = -2;
6618       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6619       orntNew[2] = ornt[2];
6620       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6621       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6622 #if 1
6623       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);
6624       for (p = 0; p < 3; ++p) {
6625         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);
6626       }
6627 #endif
6628       /* B triangle */
6629       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6630       orntNew[0] = ornt[0];
6631       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6632       orntNew[1] = ornt[1];
6633       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6634       orntNew[2] = -2;
6635       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6636       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6637 #if 1
6638       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);
6639       for (p = 0; p < 3; ++p) {
6640         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);
6641       }
6642 #endif
6643       /* C triangle */
6644       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6645       orntNew[0] = -2;
6646       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6647       orntNew[1] = ornt[1];
6648       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6649       orntNew[2] = ornt[2];
6650       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6651       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6652 #if 1
6653       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);
6654       for (p = 0; p < 3; ++p) {
6655         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);
6656       }
6657 #endif
6658       /* D triangle */
6659       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6660       orntNew[0] = 0;
6661       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6662       orntNew[1] = 0;
6663       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6664       orntNew[2] = 0;
6665       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6666       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6667 #if 1
6668       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);
6669       for (p = 0; p < 3; ++p) {
6670         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);
6671       }
6672 #endif
6673     }
6674     /*
6675      2----3----3
6676      |         |
6677      |    B    |
6678      |         |
6679      0----4--- 1
6680      |         |
6681      |    A    |
6682      |         |
6683      0----2----1
6684      */
6685     /* Hybrid cells have 4 faces */
6686     for (c = cMax; c < cEnd; ++c) {
6687       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6688       const PetscInt *cone, *ornt;
6689       PetscInt        coneNew[4], orntNew[4];
6690 
6691       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6692       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6693       /* A quad */
6694       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6695       orntNew[0] = ornt[0];
6696       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6697       orntNew[1] = ornt[1];
6698       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6699       orntNew[2] = 0;
6700       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6701       orntNew[3] = 0;
6702       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6703       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6704 #if 1
6705       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);
6706       for (p = 0; p < 4; ++p) {
6707         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);
6708       }
6709 #endif
6710       /* B quad */
6711       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6712       orntNew[0] = ornt[0];
6713       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6714       orntNew[1] = ornt[1];
6715       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6716       orntNew[2] = 0;
6717       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6718       orntNew[3] = 0;
6719       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6720       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6721 #if 1
6722       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);
6723       for (p = 0; p < 4; ++p) {
6724         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);
6725       }
6726 #endif
6727     }
6728     /* Interior split faces have 2 vertices and the same cells as the parent */
6729     ierr = DMPlexGetMaxSizes(dm, NULL, &maxSupportSize);CHKERRQ(ierr);
6730     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6731     for (f = fStart; f < fMax; ++f) {
6732       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6733 
6734       for (r = 0; r < 2; ++r) {
6735         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6736         const PetscInt *cone, *support;
6737         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6738 
6739         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6740         coneNew[0]       = vStartNew + (cone[0] - vStart);
6741         coneNew[1]       = vStartNew + (cone[1] - vStart);
6742         coneNew[(r+1)%2] = newv;
6743         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6744 #if 1
6745         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6746         for (p = 0; p < 2; ++p) {
6747           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);
6748         }
6749 #endif
6750         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6751         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6752         for (s = 0; s < supportSize; ++s) {
6753           if (support[s] >= cMax) {
6754             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6755           } else {
6756             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6757             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6758             for (c = 0; c < coneSize; ++c) {
6759               if (cone[c] == f) break;
6760             }
6761             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6762           }
6763         }
6764         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6765 #if 1
6766         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6767         for (p = 0; p < supportSize; ++p) {
6768           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);
6769         }
6770 #endif
6771       }
6772     }
6773     /* Interior cell faces have 2 vertices and 2 cells */
6774     for (c = cStart; c < cMax; ++c) {
6775       const PetscInt *cone;
6776 
6777       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6778       for (r = 0; r < 3; ++r) {
6779         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6780         PetscInt       coneNew[2];
6781         PetscInt       supportNew[2];
6782 
6783         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6784         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6785         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6786 #if 1
6787         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6788         for (p = 0; p < 2; ++p) {
6789           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);
6790         }
6791 #endif
6792         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6793         supportNew[1] = (c - cStart)*4 + 3;
6794         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6795 #if 1
6796         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6797         for (p = 0; p < 2; ++p) {
6798           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);
6799         }
6800 #endif
6801       }
6802     }
6803     /* Interior hybrid faces have 2 vertices and the same cells */
6804     for (f = fMax; f < fEnd; ++f) {
6805       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6806       const PetscInt *cone;
6807       const PetscInt *support;
6808       PetscInt        coneNew[2];
6809       PetscInt        supportNew[2];
6810       PetscInt        size, s, r;
6811 
6812       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6813       coneNew[0] = vStartNew + (cone[0] - vStart);
6814       coneNew[1] = vStartNew + (cone[1] - vStart);
6815       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6816 #if 1
6817       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6818       for (p = 0; p < 2; ++p) {
6819         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);
6820       }
6821 #endif
6822       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6823       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6824       for (s = 0; s < size; ++s) {
6825         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6826         for (r = 0; r < 2; ++r) {
6827           if (cone[r+2] == f) break;
6828         }
6829         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6830       }
6831       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6832 #if 1
6833       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6834       for (p = 0; p < size; ++p) {
6835         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);
6836       }
6837 #endif
6838     }
6839     /* Cell hybrid faces have 2 vertices and 2 cells */
6840     for (c = cMax; c < cEnd; ++c) {
6841       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6842       const PetscInt *cone;
6843       PetscInt        coneNew[2];
6844       PetscInt        supportNew[2];
6845 
6846       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6847       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6848       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6849       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6850 #if 1
6851       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6852       for (p = 0; p < 2; ++p) {
6853         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);
6854       }
6855 #endif
6856       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6857       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6858       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6859 #if 1
6860       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6861       for (p = 0; p < 2; ++p) {
6862         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);
6863       }
6864 #endif
6865     }
6866     /* Old vertices have identical supports */
6867     for (v = vStart; v < vEnd; ++v) {
6868       const PetscInt  newp = vStartNew + (v - vStart);
6869       const PetscInt *support, *cone;
6870       PetscInt        size, s;
6871 
6872       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6873       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6874       for (s = 0; s < size; ++s) {
6875         if (support[s] >= fMax) {
6876           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6877         } else {
6878           PetscInt r = 0;
6879 
6880           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6881           if (cone[1] == v) r = 1;
6882           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6883         }
6884       }
6885       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6886 #if 1
6887       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6888       for (p = 0; p < size; ++p) {
6889         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);
6890       }
6891 #endif
6892     }
6893     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6894     for (f = fStart; f < fMax; ++f) {
6895       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6896       const PetscInt *cone, *support;
6897       PetscInt        size, newSize = 2, s;
6898 
6899       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6900       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6901       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6902       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6903       for (s = 0; s < size; ++s) {
6904         PetscInt r = 0;
6905 
6906         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6907         if (support[s] >= cMax) {
6908           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6909 
6910           newSize += 1;
6911         } else {
6912           if      (cone[1] == f) r = 1;
6913           else if (cone[2] == f) r = 2;
6914           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6915           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6916 
6917           newSize += 2;
6918         }
6919       }
6920       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6921 #if 1
6922       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6923       for (p = 0; p < newSize; ++p) {
6924         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);
6925       }
6926 #endif
6927     }
6928     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6929     break;
6930   default:
6931     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6932   }
6933   PetscFunctionReturn(0);
6934 }
6935 
6936 #undef __FUNCT__
6937 #define __FUNCT__ "CellRefinerSetCoordinates"
6938 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6939 {
6940   PetscSection   coordSection, coordSectionNew;
6941   Vec            coordinates, coordinatesNew;
6942   PetscScalar   *coords, *coordsNew;
6943   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6944   PetscErrorCode ierr;
6945 
6946   PetscFunctionBegin;
6947   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6948   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6949   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6950   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6951   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6952   ierr = DMPlexGetHybridBounds(dm, NULL, &fMax, NULL, NULL);CHKERRQ(ierr);
6953   ierr = GetDepthStart_Private(depth, depthSize, NULL, NULL, NULL, &vStartNew);CHKERRQ(ierr);
6954   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6955   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &coordSectionNew);CHKERRQ(ierr);
6956   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6957   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6958   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6959   if (fMax < 0) fMax = fEnd;
6960   switch (refiner) {
6961   case 1:
6962   case 2:
6963   case 3:
6964     /* Simplicial and Hex 2D */
6965     /* All vertices have the dim coordinates */
6966     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6967       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6968       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6969     }
6970     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6971     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6972     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6973     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6974     ierr = VecCreate(PetscObjectComm((PetscObject)dm), &coordinatesNew);CHKERRQ(ierr);
6975     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6976     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6977     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6978     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6979     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6980     /* Old vertices have the same coordinates */
6981     for (v = vStart; v < vEnd; ++v) {
6982       const PetscInt newv = vStartNew + (v - vStart);
6983       PetscInt       off, offnew, d;
6984 
6985       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6986       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6987       for (d = 0; d < dim; ++d) {
6988         coordsNew[offnew+d] = coords[off+d];
6989       }
6990     }
6991     /* Face vertices have the average of endpoint coordinates */
6992     for (f = fStart; f < fMax; ++f) {
6993       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6994       const PetscInt *cone;
6995       PetscInt        coneSize, offA, offB, offnew, d;
6996 
6997       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6998       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6999       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
7000       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
7001       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
7002       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
7003       for (d = 0; d < dim; ++d) {
7004         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
7005       }
7006     }
7007     /* Just Hex 2D */
7008     if (refiner == 2) {
7009       /* Cell vertices have the average of corner coordinates */
7010       for (c = cStart; c < cEnd; ++c) {
7011         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
7012         PetscInt      *cone = NULL;
7013         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
7014 
7015         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7016         for (p = 0; p < closureSize*2; p += 2) {
7017           const PetscInt point = cone[p];
7018           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
7019         }
7020         if (coneSize != 4) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
7021         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
7022         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
7023         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
7024         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
7025         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
7026         for (d = 0; d < dim; ++d) {
7027           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
7028         }
7029         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
7030       }
7031     }
7032     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
7033     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
7034     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
7035     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
7036     ierr = PetscSectionDestroy(&coordSectionNew);CHKERRQ(ierr);
7037     break;
7038   default:
7039     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7040   }
7041   PetscFunctionReturn(0);
7042 }
7043 
7044 #undef __FUNCT__
7045 #define __FUNCT__ "DMPlexCreateProcessSF"
7046 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
7047 {
7048   PetscInt           numRoots, numLeaves, l;
7049   const PetscInt    *localPoints;
7050   const PetscSFNode *remotePoints;
7051   PetscInt          *localPointsNew;
7052   PetscSFNode       *remotePointsNew;
7053   PetscInt          *ranks, *ranksNew;
7054   PetscErrorCode     ierr;
7055 
7056   PetscFunctionBegin;
7057   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7058   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
7059   for (l = 0; l < numLeaves; ++l) {
7060     ranks[l] = remotePoints[l].rank;
7061   }
7062   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
7063   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
7064   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7065   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7066   for (l = 0; l < numLeaves; ++l) {
7067     ranksNew[l]              = ranks[l];
7068     localPointsNew[l]        = l;
7069     remotePointsNew[l].index = 0;
7070     remotePointsNew[l].rank  = ranksNew[l];
7071   }
7072   ierr = PetscFree(ranks);CHKERRQ(ierr);
7073   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
7074   ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm), sfProcess);CHKERRQ(ierr);
7075   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7076   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7077   PetscFunctionReturn(0);
7078 }
7079 
7080 #undef __FUNCT__
7081 #define __FUNCT__ "CellRefinerCreateSF"
7082 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7083 {
7084   PetscSF            sf, sfNew, sfProcess;
7085   IS                 processRanks;
7086   MPI_Datatype       depthType;
7087   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7088   const PetscInt    *localPoints, *neighbors;
7089   const PetscSFNode *remotePoints;
7090   PetscInt          *localPointsNew;
7091   PetscSFNode       *remotePointsNew;
7092   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7093   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7094   PetscErrorCode     ierr;
7095 
7096   PetscFunctionBegin;
7097   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7098   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7099   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7100   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7101   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7102   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7103   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7104   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7105   switch (refiner) {
7106   case 3:
7107     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7108     cMax = PetscMin(cEnd, cMax);
7109     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7110     fMax = PetscMin(fEnd, fMax);
7111   }
7112   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7113   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7114   /* Caculate size of new SF */
7115   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7116   if (numRoots < 0) PetscFunctionReturn(0);
7117   for (l = 0; l < numLeaves; ++l) {
7118     const PetscInt p = localPoints[l];
7119 
7120     switch (refiner) {
7121     case 1:
7122       /* Simplicial 2D */
7123       if ((p >= vStart) && (p < vEnd)) {
7124         /* Old vertices stay the same */
7125         ++numLeavesNew;
7126       } else if ((p >= fStart) && (p < fEnd)) {
7127         /* Old faces add new faces and vertex */
7128         numLeavesNew += 1 + 2;
7129       } else if ((p >= cStart) && (p < cEnd)) {
7130         /* Old cells add new cells and interior faces */
7131         numLeavesNew += 4 + 3;
7132       }
7133       break;
7134     case 2:
7135       /* Hex 2D */
7136       if ((p >= vStart) && (p < vEnd)) {
7137         /* Old vertices stay the same */
7138         ++numLeavesNew;
7139       } else if ((p >= fStart) && (p < fEnd)) {
7140         /* Old faces add new faces and vertex */
7141         numLeavesNew += 1 + 2;
7142       } else if ((p >= cStart) && (p < cEnd)) {
7143         /* Old cells add new cells and interior faces */
7144         numLeavesNew += 4 + 4;
7145       }
7146       break;
7147     default:
7148       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7149     }
7150   }
7151   /* Communicate depthSizes for each remote rank */
7152   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7153   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7154   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7155   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);
7156   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7157   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7158   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7159   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7160   for (n = 0; n < numNeighbors; ++n) {
7161     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7162   }
7163   depthSizeOld[depth]   = cMax;
7164   depthSizeOld[0]       = vMax;
7165   depthSizeOld[depth-1] = fMax;
7166   depthSizeOld[1]       = eMax;
7167 
7168   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7169   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7170 
7171   depthSizeOld[depth]   = cEnd - cStart;
7172   depthSizeOld[0]       = vEnd - vStart;
7173   depthSizeOld[depth-1] = fEnd - fStart;
7174   depthSizeOld[1]       = eEnd - eStart;
7175 
7176   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7177   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7178   for (n = 0; n < numNeighbors; ++n) {
7179     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7180   }
7181   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7182   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7183   /* Calculate new point SF */
7184   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7185   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7186   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7187   for (l = 0, m = 0; l < numLeaves; ++l) {
7188     PetscInt    p     = localPoints[l];
7189     PetscInt    rp    = remotePoints[l].index, n;
7190     PetscMPIInt rrank = remotePoints[l].rank;
7191 
7192     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7193     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7194     switch (refiner) {
7195     case 1:
7196       /* Simplicial 2D */
7197       if ((p >= vStart) && (p < vEnd)) {
7198         /* Old vertices stay the same */
7199         localPointsNew[m]        = vStartNew     + (p  - vStart);
7200         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7201         remotePointsNew[m].rank  = rrank;
7202         ++m;
7203       } else if ((p >= fStart) && (p < fEnd)) {
7204         /* Old faces add new faces and vertex */
7205         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7206         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7207         remotePointsNew[m].rank  = rrank;
7208         ++m;
7209         for (r = 0; r < 2; ++r, ++m) {
7210           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7211           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7212           remotePointsNew[m].rank  = rrank;
7213         }
7214       } else if ((p >= cStart) && (p < cEnd)) {
7215         /* Old cells add new cells and interior faces */
7216         for (r = 0; r < 4; ++r, ++m) {
7217           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7218           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7219           remotePointsNew[m].rank  = rrank;
7220         }
7221         for (r = 0; r < 3; ++r, ++m) {
7222           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7223           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7224           remotePointsNew[m].rank  = rrank;
7225         }
7226       }
7227       break;
7228     case 2:
7229       /* Hex 2D */
7230       if ((p >= vStart) && (p < vEnd)) {
7231         /* Old vertices stay the same */
7232         localPointsNew[m]        = vStartNew     + (p  - vStart);
7233         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7234         remotePointsNew[m].rank  = rrank;
7235         ++m;
7236       } else if ((p >= fStart) && (p < fEnd)) {
7237         /* Old faces add new faces and vertex */
7238         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7239         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7240         remotePointsNew[m].rank  = rrank;
7241         ++m;
7242         for (r = 0; r < 2; ++r, ++m) {
7243           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7244           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7245           remotePointsNew[m].rank  = rrank;
7246         }
7247       } else if ((p >= cStart) && (p < cEnd)) {
7248         /* Old cells add new cells and interior faces */
7249         for (r = 0; r < 4; ++r, ++m) {
7250           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7251           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7252           remotePointsNew[m].rank  = rrank;
7253         }
7254         for (r = 0; r < 4; ++r, ++m) {
7255           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7256           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7257           remotePointsNew[m].rank  = rrank;
7258         }
7259       }
7260       break;
7261     case 3:
7262       /* Hybrid simplicial 2D */
7263       if ((p >= vStart) && (p < vEnd)) {
7264         /* Old vertices stay the same */
7265         localPointsNew[m]        = vStartNew     + (p  - vStart);
7266         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7267         remotePointsNew[m].rank  = rrank;
7268         ++m;
7269       } else if ((p >= fStart) && (p < fMax)) {
7270         /* Old interior faces add new faces and vertex */
7271         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7272         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7273         remotePointsNew[m].rank  = rrank;
7274         ++m;
7275         for (r = 0; r < 2; ++r, ++m) {
7276           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7277           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7278           remotePointsNew[m].rank  = rrank;
7279         }
7280       } else if ((p >= fMax) && (p < fEnd)) {
7281         /* Old hybrid faces stay the same */
7282         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7283         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7284         remotePointsNew[m].rank  = rrank;
7285         ++m;
7286       } else if ((p >= cStart) && (p < cMax)) {
7287         /* Old interior cells add new cells and interior faces */
7288         for (r = 0; r < 4; ++r, ++m) {
7289           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7290           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7291           remotePointsNew[m].rank  = rrank;
7292         }
7293         for (r = 0; r < 3; ++r, ++m) {
7294           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7295           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7296           remotePointsNew[m].rank  = rrank;
7297         }
7298       } else if ((p >= cStart) && (p < cMax)) {
7299         /* Old hybrid cells add new cells and hybrid face */
7300         for (r = 0; r < 2; ++r, ++m) {
7301           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7302           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7303           remotePointsNew[m].rank  = rrank;
7304         }
7305         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7306         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]);
7307         remotePointsNew[m].rank  = rrank;
7308         ++m;
7309       }
7310       break;
7311     default:
7312       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7313     }
7314   }
7315   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7316   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7317   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7318   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7319   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7320   PetscFunctionReturn(0);
7321 }
7322 
7323 #undef __FUNCT__
7324 #define __FUNCT__ "CellRefinerCreateLabels"
7325 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7326 {
7327   PetscInt       numLabels, l;
7328   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7329   PetscErrorCode ierr;
7330 
7331   PetscFunctionBegin;
7332   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7333   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7334   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7335   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7336 
7337   cStartNew = 0;
7338   vStartNew = depthSize[2];
7339   fStartNew = depthSize[2] + depthSize[0];
7340 
7341   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7342   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7343   switch (refiner) {
7344   case 3:
7345     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7346     cMax = PetscMin(cEnd, cMax);
7347     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7348     fMax = PetscMin(fEnd, fMax);
7349   }
7350   for (l = 0; l < numLabels; ++l) {
7351     DMLabel         label, labelNew;
7352     const char     *lname;
7353     PetscBool       isDepth;
7354     IS              valueIS;
7355     const PetscInt *values;
7356     PetscInt        numValues, val;
7357 
7358     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7359     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7360     if (isDepth) continue;
7361     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7362     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7363     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7364     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7365     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7366     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7367     for (val = 0; val < numValues; ++val) {
7368       IS              pointIS;
7369       const PetscInt *points;
7370       PetscInt        numPoints, n;
7371 
7372       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7373       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7374       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7375       for (n = 0; n < numPoints; ++n) {
7376         const PetscInt p = points[n];
7377         switch (refiner) {
7378         case 1:
7379           /* Simplicial 2D */
7380           if ((p >= vStart) && (p < vEnd)) {
7381             /* Old vertices stay the same */
7382             newp = vStartNew + (p - vStart);
7383             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7384           } else if ((p >= fStart) && (p < fEnd)) {
7385             /* Old faces add new faces and vertex */
7386             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7387             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7388             for (r = 0; r < 2; ++r) {
7389               newp = fStartNew + (p - fStart)*2 + r;
7390               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7391             }
7392           } else if ((p >= cStart) && (p < cEnd)) {
7393             /* Old cells add new cells and interior faces */
7394             for (r = 0; r < 4; ++r) {
7395               newp = cStartNew + (p - cStart)*4 + r;
7396               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7397             }
7398             for (r = 0; r < 3; ++r) {
7399               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7400               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7401             }
7402           }
7403           break;
7404         case 2:
7405           /* Hex 2D */
7406           if ((p >= vStart) && (p < vEnd)) {
7407             /* Old vertices stay the same */
7408             newp = vStartNew + (p - vStart);
7409             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7410           } else if ((p >= fStart) && (p < fEnd)) {
7411             /* Old faces add new faces and vertex */
7412             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7413             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7414             for (r = 0; r < 2; ++r) {
7415               newp = fStartNew + (p - fStart)*2 + r;
7416               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7417             }
7418           } else if ((p >= cStart) && (p < cEnd)) {
7419             /* Old cells add new cells and interior faces and vertex */
7420             for (r = 0; r < 4; ++r) {
7421               newp = cStartNew + (p - cStart)*4 + r;
7422               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7423             }
7424             for (r = 0; r < 4; ++r) {
7425               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7426               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7427             }
7428             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7429             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7430           }
7431           break;
7432         case 3:
7433           /* Hybrid simplicial 2D */
7434           if ((p >= vStart) && (p < vEnd)) {
7435             /* Old vertices stay the same */
7436             newp = vStartNew + (p - vStart);
7437             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7438           } else if ((p >= fStart) && (p < fMax)) {
7439             /* Old interior faces add new faces and vertex */
7440             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7441             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7442             for (r = 0; r < 2; ++r) {
7443               newp = fStartNew + (p - fStart)*2 + r;
7444               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7445             }
7446           } else if ((p >= fMax) && (p < fEnd)) {
7447             /* Old hybrid faces stay the same */
7448             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7449             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7450           } else if ((p >= cStart) && (p < cMax)) {
7451             /* Old interior cells add new cells and interior faces */
7452             for (r = 0; r < 4; ++r) {
7453               newp = cStartNew + (p - cStart)*4 + r;
7454               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7455             }
7456             for (r = 0; r < 3; ++r) {
7457               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7458               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7459             }
7460           } else if ((p >= cMax) && (p < cEnd)) {
7461             /* Old hybrid cells add new cells and hybrid face */
7462             for (r = 0; r < 2; ++r) {
7463               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7464               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7465             }
7466             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7467             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7468           }
7469           break;
7470         default:
7471           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7472         }
7473       }
7474       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7475       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7476     }
7477     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7478     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7479     if (0) {
7480       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7481       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7482       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7483     }
7484   }
7485   PetscFunctionReturn(0);
7486 }
7487 
7488 #undef __FUNCT__
7489 #define __FUNCT__ "DMPlexRefine_Uniform"
7490 /* This will only work for interpolated meshes */
7491 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7492 {
7493   DM             rdm;
7494   PetscInt      *depthSize;
7495   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7496   PetscErrorCode ierr;
7497 
7498   PetscFunctionBegin;
7499   ierr = DMCreate(PetscObjectComm((PetscObject)dm), &rdm);CHKERRQ(ierr);
7500   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7501   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7502   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7503   /* Calculate number of new points of each depth */
7504   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7505   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7506   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7507   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7508   /* Step 1: Set chart */
7509   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7510   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7511   /* Step 2: Set cone/support sizes */
7512   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7513   /* Step 3: Setup refined DM */
7514   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7515   /* Step 4: Set cones and supports */
7516   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7517   /* Step 5: Stratify */
7518   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7519   /* Step 6: Set coordinates for vertices */
7520   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7521   /* Step 7: Create pointSF */
7522   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7523   /* Step 8: Create labels */
7524   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7525   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7526 
7527   *dmRefined = rdm;
7528   PetscFunctionReturn(0);
7529 }
7530 
7531 #undef __FUNCT__
7532 #define __FUNCT__ "DMPlexSetRefinementUniform"
7533 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7534 {
7535   DM_Plex *mesh = (DM_Plex*) dm->data;
7536 
7537   PetscFunctionBegin;
7538   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7539   mesh->refinementUniform = refinementUniform;
7540   PetscFunctionReturn(0);
7541 }
7542 
7543 #undef __FUNCT__
7544 #define __FUNCT__ "DMPlexGetRefinementUniform"
7545 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7546 {
7547   DM_Plex *mesh = (DM_Plex*) dm->data;
7548 
7549   PetscFunctionBegin;
7550   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7551   PetscValidPointer(refinementUniform,  2);
7552   *refinementUniform = mesh->refinementUniform;
7553   PetscFunctionReturn(0);
7554 }
7555 
7556 #undef __FUNCT__
7557 #define __FUNCT__ "DMPlexSetRefinementLimit"
7558 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7559 {
7560   DM_Plex *mesh = (DM_Plex*) dm->data;
7561 
7562   PetscFunctionBegin;
7563   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7564   mesh->refinementLimit = refinementLimit;
7565   PetscFunctionReturn(0);
7566 }
7567 
7568 #undef __FUNCT__
7569 #define __FUNCT__ "DMPlexGetRefinementLimit"
7570 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7571 {
7572   DM_Plex *mesh = (DM_Plex*) dm->data;
7573 
7574   PetscFunctionBegin;
7575   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7576   PetscValidPointer(refinementLimit,  2);
7577   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7578   *refinementLimit = mesh->refinementLimit;
7579   PetscFunctionReturn(0);
7580 }
7581 
7582 #undef __FUNCT__
7583 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7584 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7585 {
7586   PetscInt       dim, cStart, coneSize, cMax;
7587   PetscErrorCode ierr;
7588 
7589   PetscFunctionBegin;
7590   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7591   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, NULL);CHKERRQ(ierr);
7592   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7593   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
7594   switch (dim) {
7595   case 2:
7596     switch (coneSize) {
7597     case 3:
7598       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7599       else *cellRefiner = 1; /* Triangular */
7600       break;
7601     case 4:
7602       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7603       else *cellRefiner = 2; /* Quadrilateral */
7604       break;
7605     default:
7606       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7607     }
7608     break;
7609   default:
7610     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7611   }
7612   PetscFunctionReturn(0);
7613 }
7614 
7615 #undef __FUNCT__
7616 #define __FUNCT__ "DMRefine_Plex"
7617 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7618 {
7619   PetscReal      refinementLimit;
7620   PetscInt       dim, cStart, cEnd;
7621   char           genname[1024], *name = NULL;
7622   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7623   PetscErrorCode ierr;
7624 
7625   PetscFunctionBegin;
7626   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7627   if (isUniform) {
7628     CellRefiner cellRefiner;
7629 
7630     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7631     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7632     PetscFunctionReturn(0);
7633   }
7634   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7635   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7636   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7637   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7638   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7639   if (flg) name = genname;
7640   if (name) {
7641     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7642     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7643     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7644   }
7645   switch (dim) {
7646   case 2:
7647     if (!name || isTriangle) {
7648 #if defined(PETSC_HAVE_TRIANGLE)
7649       double  *maxVolumes;
7650       PetscInt c;
7651 
7652       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7653       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7654       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7655 #else
7656       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7657 #endif
7658     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7659     break;
7660   case 3:
7661     if (!name || isCTetgen) {
7662 #if defined(PETSC_HAVE_CTETGEN)
7663       PetscReal *maxVolumes;
7664       PetscInt   c;
7665 
7666       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7667       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7668       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7669 #else
7670       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7671 #endif
7672     } else if (isTetgen) {
7673 #if defined(PETSC_HAVE_TETGEN)
7674       double  *maxVolumes;
7675       PetscInt c;
7676 
7677       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7678       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7679       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7680 #else
7681       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7682 #endif
7683     } else SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7684     break;
7685   default:
7686     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7687   }
7688   PetscFunctionReturn(0);
7689 }
7690 
7691 #undef __FUNCT__
7692 #define __FUNCT__ "DMPlexGetDepth"
7693 /*@
7694   DMPlexGetDepth - get the number of strata
7695 
7696   Not Collective
7697 
7698   Input Parameters:
7699 . dm           - The DMPlex object
7700 
7701   Output Parameters:
7702 . depth - number of strata
7703 
7704   Level: developer
7705 
7706   Notes:
7707   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7708 
7709 .keywords: mesh, points
7710 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7711 @*/
7712 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7713 {
7714   PetscInt       d;
7715   PetscErrorCode ierr;
7716 
7717   PetscFunctionBegin;
7718   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7719   PetscValidPointer(depth, 2);
7720   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7721   *depth = d-1;
7722   PetscFunctionReturn(0);
7723 }
7724 
7725 #undef __FUNCT__
7726 #define __FUNCT__ "DMPlexGetDepthStratum"
7727 /*@
7728   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7729 
7730   Not Collective
7731 
7732   Input Parameters:
7733 + dm           - The DMPlex object
7734 - stratumValue - The requested depth
7735 
7736   Output Parameters:
7737 + start - The first point at this depth
7738 - end   - One beyond the last point at this depth
7739 
7740   Level: developer
7741 
7742 .keywords: mesh, points
7743 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7744 @*/
7745 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7746 {
7747   DM_Plex       *mesh = (DM_Plex*) dm->data;
7748   DMLabel        next  = mesh->labels;
7749   PetscBool      flg   = PETSC_FALSE;
7750   PetscInt       depth;
7751   PetscErrorCode ierr;
7752 
7753   PetscFunctionBegin;
7754   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7755   if (stratumValue < 0) {
7756     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7757     PetscFunctionReturn(0);
7758   } else {
7759     PetscInt pStart, pEnd;
7760 
7761     if (start) *start = 0;
7762     if (end)   *end   = 0;
7763     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7764     if (pStart == pEnd) PetscFunctionReturn(0);
7765   }
7766   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7767   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7768   /* We should have a generic GetLabel() and a Label class */
7769   while (next) {
7770     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7771     if (flg) break;
7772     next = next->next;
7773   }
7774   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7775   depth = stratumValue;
7776   if ((depth < 0) || (depth >= next->numStrata)) {
7777     if (start) *start = 0;
7778     if (end)   *end   = 0;
7779   } else {
7780     if (start) *start = next->points[next->stratumOffsets[depth]];
7781     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7782   }
7783   PetscFunctionReturn(0);
7784 }
7785 
7786 #undef __FUNCT__
7787 #define __FUNCT__ "DMPlexGetHeightStratum"
7788 /*@
7789   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7790 
7791   Not Collective
7792 
7793   Input Parameters:
7794 + dm           - The DMPlex object
7795 - stratumValue - The requested height
7796 
7797   Output Parameters:
7798 + start - The first point at this height
7799 - end   - One beyond the last point at this height
7800 
7801   Level: developer
7802 
7803 .keywords: mesh, points
7804 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7805 @*/
7806 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7807 {
7808   DM_Plex       *mesh = (DM_Plex*) dm->data;
7809   DMLabel        next  = mesh->labels;
7810   PetscBool      flg   = PETSC_FALSE;
7811   PetscInt       depth;
7812   PetscErrorCode ierr;
7813 
7814   PetscFunctionBegin;
7815   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7816   if (stratumValue < 0) {
7817     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7818   } else {
7819     PetscInt pStart, pEnd;
7820 
7821     if (start) *start = 0;
7822     if (end)   *end   = 0;
7823     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7824     if (pStart == pEnd) PetscFunctionReturn(0);
7825   }
7826   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7827   if (!flg) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7828   /* We should have a generic GetLabel() and a Label class */
7829   while (next) {
7830     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7831     if (flg) break;
7832     next = next->next;
7833   }
7834   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7835   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7836   if ((depth < 0) || (depth >= next->numStrata)) {
7837     if (start) *start = 0;
7838     if (end)   *end   = 0;
7839   } else {
7840     if (start) *start = next->points[next->stratumOffsets[depth]];
7841     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7842   }
7843   PetscFunctionReturn(0);
7844 }
7845 
7846 #undef __FUNCT__
7847 #define __FUNCT__ "DMPlexCreateSectionInitial"
7848 /* Set the number of dof on each point and separate by fields */
7849 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7850 {
7851   PetscInt      *numDofTot;
7852   PetscInt       pStart = 0, pEnd = 0;
7853   PetscInt       p, d, f;
7854   PetscErrorCode ierr;
7855 
7856   PetscFunctionBegin;
7857   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7858   for (d = 0; d <= dim; ++d) {
7859     numDofTot[d] = 0;
7860     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7861   }
7862   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), section);CHKERRQ(ierr);
7863   if (numFields > 0) {
7864     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7865     if (numComp) {
7866       for (f = 0; f < numFields; ++f) {
7867         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7868       }
7869     }
7870   }
7871   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7872   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7873   for (d = 0; d <= dim; ++d) {
7874     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7875     for (p = pStart; p < pEnd; ++p) {
7876       for (f = 0; f < numFields; ++f) {
7877         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7878       }
7879       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7880     }
7881   }
7882   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7883   PetscFunctionReturn(0);
7884 }
7885 
7886 #undef __FUNCT__
7887 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7888 /* Set the number of dof on each point and separate by fields
7889    If constDof is PETSC_DETERMINE, constrain every dof on the point
7890 */
7891 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7892 {
7893   PetscInt       numFields;
7894   PetscInt       bc;
7895   PetscErrorCode ierr;
7896 
7897   PetscFunctionBegin;
7898   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7899   for (bc = 0; bc < numBC; ++bc) {
7900     PetscInt        field = 0;
7901     const PetscInt *idx;
7902     PetscInt        n, i;
7903 
7904     if (numFields) field = bcField[bc];
7905     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7906     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7907     for (i = 0; i < n; ++i) {
7908       const PetscInt p        = idx[i];
7909       PetscInt       numConst = constDof;
7910 
7911       /* Constrain every dof on the point */
7912       if (numConst < 0) {
7913         if (numFields) {
7914           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7915         } else {
7916           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7917         }
7918       }
7919       if (numFields) {
7920         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7921       }
7922       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7923     }
7924     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7925   }
7926   PetscFunctionReturn(0);
7927 }
7928 
7929 #undef __FUNCT__
7930 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7931 /* Set the constrained indices on each point and separate by fields */
7932 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7933 {
7934   PetscInt      *maxConstraints;
7935   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7936   PetscErrorCode ierr;
7937 
7938   PetscFunctionBegin;
7939   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7940   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7941   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7942   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7943   for (p = pStart; p < pEnd; ++p) {
7944     PetscInt cdof;
7945 
7946     if (numFields) {
7947       for (f = 0; f < numFields; ++f) {
7948         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7949         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7950       }
7951     } else {
7952       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7953       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7954     }
7955   }
7956   for (f = 0; f < numFields; ++f) {
7957     maxConstraints[numFields] += maxConstraints[f];
7958   }
7959   if (maxConstraints[numFields]) {
7960     PetscInt *indices;
7961 
7962     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7963     for (p = pStart; p < pEnd; ++p) {
7964       PetscInt cdof, d;
7965 
7966       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7967       if (cdof) {
7968         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7969         if (numFields) {
7970           PetscInt numConst = 0, foff = 0;
7971 
7972           for (f = 0; f < numFields; ++f) {
7973             PetscInt cfdof, fdof;
7974 
7975             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7976             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7977             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7978             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7979             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7980             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7981             numConst += cfdof;
7982             foff     += fdof;
7983           }
7984           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7985         } else {
7986           for (d = 0; d < cdof; ++d) indices[d] = d;
7987         }
7988         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7989       }
7990     }
7991     ierr = PetscFree(indices);CHKERRQ(ierr);
7992   }
7993   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7994   PetscFunctionReturn(0);
7995 }
7996 
7997 #undef __FUNCT__
7998 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7999 /* Set the constrained field indices on each point */
8000 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
8001 {
8002   const PetscInt *points, *indices;
8003   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
8004   PetscErrorCode  ierr;
8005 
8006   PetscFunctionBegin;
8007   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8008   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8009 
8010   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8011   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8012   if (!constraintIndices) {
8013     PetscInt *idx, i;
8014 
8015     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8016     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8017     for (i = 0; i < maxDof; ++i) idx[i] = i;
8018     for (p = 0; p < numPoints; ++p) {
8019       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8020     }
8021     ierr = PetscFree(idx);CHKERRQ(ierr);
8022   } else {
8023     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8024     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8025     for (p = 0; p < numPoints; ++p) {
8026       PetscInt fcdof;
8027 
8028       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8029       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);
8030       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8031     }
8032     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8033   }
8034   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8035   PetscFunctionReturn(0);
8036 }
8037 
8038 #undef __FUNCT__
8039 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8040 /* Set the constrained indices on each point and separate by fields */
8041 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8042 {
8043   PetscInt      *indices;
8044   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8045   PetscErrorCode ierr;
8046 
8047   PetscFunctionBegin;
8048   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8049   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8050   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8051   if (!numFields) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8052   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8053   for (p = pStart; p < pEnd; ++p) {
8054     PetscInt cdof, d;
8055 
8056     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8057     if (cdof) {
8058       PetscInt numConst = 0, foff = 0;
8059 
8060       for (f = 0; f < numFields; ++f) {
8061         const PetscInt *fcind;
8062         PetscInt        fdof, fcdof;
8063 
8064         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8065         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8066         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8067         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8068         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
8069         foff     += fdof;
8070         numConst += fcdof;
8071       }
8072       if (cdof != numConst) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8073       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8074     }
8075   }
8076   ierr = PetscFree(indices);CHKERRQ(ierr);
8077   PetscFunctionReturn(0);
8078 }
8079 
8080 #undef __FUNCT__
8081 #define __FUNCT__ "DMPlexCreateSection"
8082 /*@C
8083   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8084 
8085   Not Collective
8086 
8087   Input Parameters:
8088 + dm        - The DMPlex object
8089 . dim       - The spatial dimension of the problem
8090 . numFields - The number of fields in the problem
8091 . numComp   - An array of size numFields that holds the number of components for each field
8092 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8093 . numBC     - The number of boundary conditions
8094 . bcField   - An array of size numBC giving the field number for each boundry condition
8095 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8096 
8097   Output Parameter:
8098 . section - The PetscSection object
8099 
8100   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
8101   nubmer of dof for field 0 on each edge.
8102 
8103   Level: developer
8104 
8105 .keywords: mesh, elements
8106 .seealso: DMPlexCreate(), PetscSectionCreate()
8107 @*/
8108 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8109 {
8110   PetscErrorCode ierr;
8111 
8112   PetscFunctionBegin;
8113   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8114   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8115   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8116   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8117   {
8118     PetscBool view = PETSC_FALSE;
8119 
8120     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8121     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8122   }
8123   PetscFunctionReturn(0);
8124 }
8125 
8126 #undef __FUNCT__
8127 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8128 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8129 {
8130   PetscSection   section;
8131   PetscErrorCode ierr;
8132 
8133   PetscFunctionBegin;
8134   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8135   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
8136   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8137   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
8138   PetscFunctionReturn(0);
8139 }
8140 
8141 #undef __FUNCT__
8142 #define __FUNCT__ "DMPlexGetCoordinateSection"
8143 /*@
8144   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8145 
8146   Not Collective
8147 
8148   Input Parameter:
8149 . dm - The DMPlex object
8150 
8151   Output Parameter:
8152 . section - The PetscSection object
8153 
8154   Level: intermediate
8155 
8156 .keywords: mesh, coordinates
8157 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8158 @*/
8159 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8160 {
8161   DM             cdm;
8162   PetscErrorCode ierr;
8163 
8164   PetscFunctionBegin;
8165   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8166   PetscValidPointer(section, 2);
8167   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8168   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8169   PetscFunctionReturn(0);
8170 }
8171 
8172 #undef __FUNCT__
8173 #define __FUNCT__ "DMPlexSetCoordinateSection"
8174 /*@
8175   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8176 
8177   Not Collective
8178 
8179   Input Parameters:
8180 + dm      - The DMPlex object
8181 - section - The PetscSection object
8182 
8183   Level: intermediate
8184 
8185 .keywords: mesh, coordinates
8186 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8187 @*/
8188 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8189 {
8190   DM             cdm;
8191   PetscErrorCode ierr;
8192 
8193   PetscFunctionBegin;
8194   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
8195   PetscValidHeaderSpecific(section,PETSC_SECTION_CLASSID,2);
8196   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8197   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8198   PetscFunctionReturn(0);
8199 }
8200 
8201 #undef __FUNCT__
8202 #define __FUNCT__ "DMPlexGetConeSection"
8203 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8204 {
8205   DM_Plex *mesh = (DM_Plex*) dm->data;
8206 
8207   PetscFunctionBegin;
8208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8209   if (section) *section = mesh->coneSection;
8210   PetscFunctionReturn(0);
8211 }
8212 
8213 #undef __FUNCT__
8214 #define __FUNCT__ "DMPlexGetCones"
8215 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8216 {
8217   DM_Plex *mesh = (DM_Plex*) dm->data;
8218 
8219   PetscFunctionBegin;
8220   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8221   if (cones) *cones = mesh->cones;
8222   PetscFunctionReturn(0);
8223 }
8224 
8225 #undef __FUNCT__
8226 #define __FUNCT__ "DMPlexGetConeOrientations"
8227 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8228 {
8229   DM_Plex *mesh = (DM_Plex*) dm->data;
8230 
8231   PetscFunctionBegin;
8232   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8233   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8234   PetscFunctionReturn(0);
8235 }
8236 
8237 #undef __FUNCT__
8238 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8239 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8240 {
8241   const PetscInt embedDim = 2;
8242   PetscReal      x        = PetscRealPart(point[0]);
8243   PetscReal      y        = PetscRealPart(point[1]);
8244   PetscReal      v0[2], J[4], invJ[4], detJ;
8245   PetscReal      xi, eta;
8246   PetscErrorCode ierr;
8247 
8248   PetscFunctionBegin;
8249   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8250   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8251   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8252 
8253   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8254   else *cell = -1;
8255   PetscFunctionReturn(0);
8256 }
8257 
8258 #undef __FUNCT__
8259 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8260 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8261 {
8262   PetscSection       coordSection;
8263   Vec                coordsLocal;
8264   const PetscScalar *coords;
8265   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8266   PetscReal          x         = PetscRealPart(point[0]);
8267   PetscReal          y         = PetscRealPart(point[1]);
8268   PetscInt           crossings = 0, f;
8269   PetscErrorCode     ierr;
8270 
8271   PetscFunctionBegin;
8272   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8273   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8274   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8275   for (f = 0; f < 4; ++f) {
8276     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8277     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8278     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8279     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8280     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8281     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8282     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8283     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8284     if ((cond1 || cond2)  && above) ++crossings;
8285   }
8286   if (crossings % 2) *cell = c;
8287   else *cell = -1;
8288   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8289   PetscFunctionReturn(0);
8290 }
8291 
8292 #undef __FUNCT__
8293 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8294 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8295 {
8296   const PetscInt embedDim = 3;
8297   PetscReal      v0[3], J[9], invJ[9], detJ;
8298   PetscReal      x = PetscRealPart(point[0]);
8299   PetscReal      y = PetscRealPart(point[1]);
8300   PetscReal      z = PetscRealPart(point[2]);
8301   PetscReal      xi, eta, zeta;
8302   PetscErrorCode ierr;
8303 
8304   PetscFunctionBegin;
8305   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8306   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8307   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8308   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8309 
8310   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8311   else *cell = -1;
8312   PetscFunctionReturn(0);
8313 }
8314 
8315 #undef __FUNCT__
8316 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8317 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8318 {
8319   PetscSection       coordSection;
8320   Vec                coordsLocal;
8321   const PetscScalar *coords;
8322   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8323                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8324   PetscBool          found = PETSC_TRUE;
8325   PetscInt           f;
8326   PetscErrorCode     ierr;
8327 
8328   PetscFunctionBegin;
8329   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8330   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8331   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8332   for (f = 0; f < 6; ++f) {
8333     /* Check the point is under plane */
8334     /*   Get face normal */
8335     PetscReal v_i[3];
8336     PetscReal v_j[3];
8337     PetscReal normal[3];
8338     PetscReal pp[3];
8339     PetscReal dot;
8340 
8341     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8342     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8343     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8344     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8345     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8346     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8347     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8348     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8349     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8350     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8351     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8352     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8353     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8354 
8355     /* Check that projected point is in face (2D location problem) */
8356     if (dot < 0.0) {
8357       found = PETSC_FALSE;
8358       break;
8359     }
8360   }
8361   if (found) *cell = c;
8362   else *cell = -1;
8363   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, NULL, &coords);CHKERRQ(ierr);
8364   PetscFunctionReturn(0);
8365 }
8366 
8367 #undef __FUNCT__
8368 #define __FUNCT__ "DMLocatePoints_Plex"
8369 /*
8370  Need to implement using the guess
8371 */
8372 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8373 {
8374   PetscInt       cell = -1 /*, guess = -1*/;
8375   PetscInt       bs, numPoints, p;
8376   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8377   PetscInt      *cells;
8378   PetscScalar   *a;
8379   PetscErrorCode ierr;
8380 
8381   PetscFunctionBegin;
8382   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8383   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8384   ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
8385   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8386   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8387   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8388   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8389   if (bs != dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
8390   numPoints /= bs;
8391   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8392   for (p = 0; p < numPoints; ++p) {
8393     const PetscScalar *point = &a[p*bs];
8394 
8395     switch (dim) {
8396     case 2:
8397       for (c = cStart; c < cEnd; ++c) {
8398         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8399         switch (coneSize) {
8400         case 3:
8401           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8402           break;
8403         case 4:
8404           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8405           break;
8406         default:
8407           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8408         }
8409         if (cell >= 0) break;
8410       }
8411       break;
8412     case 3:
8413       for (c = cStart; c < cEnd; ++c) {
8414         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8415         switch (coneSize) {
8416         case 4:
8417           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8418           break;
8419         case 8:
8420           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8421           break;
8422         default:
8423           SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8424         }
8425         if (cell >= 0) break;
8426       }
8427       break;
8428     default:
8429       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8430     }
8431     cells[p] = cell;
8432   }
8433   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8434   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8435   PetscFunctionReturn(0);
8436 }
8437 
8438 /******************************** FEM Support **********************************/
8439 
8440 #undef __FUNCT__
8441 #define __FUNCT__ "DMPlexVecGetClosure"
8442 /*@C
8443   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8444 
8445   Not collective
8446 
8447   Input Parameters:
8448 + dm - The DM
8449 . section - The section describing the layout in v, or NULL to use the default section
8450 . v - The local vector
8451 - point - The sieve point in the DM
8452 
8453   Output Parameters:
8454 + csize - The number of values in the closure, or NULL
8455 - values - The array of values, which is a borrowed array and should not be freed
8456 
8457   Level: intermediate
8458 
8459 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8460 @*/
8461 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8462 {
8463   PetscScalar   *array, *vArray;
8464   PetscInt      *points = NULL;
8465   PetscInt       offsets[32];
8466   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8467   PetscErrorCode ierr;
8468 
8469   PetscFunctionBegin;
8470   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8471   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8472   if (!section) {
8473     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8474   }
8475   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8476   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8477   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8478   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8479   /* Compress out points not in the section */
8480   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8481   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8482     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8483       points[q*2]   = points[p];
8484       points[q*2+1] = points[p+1];
8485       ++q;
8486     }
8487   }
8488   numPoints = q;
8489   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8490     PetscInt dof, fdof;
8491 
8492     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8493     for (f = 0; f < numFields; ++f) {
8494       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8495       offsets[f+1] += fdof;
8496     }
8497     size += dof;
8498   }
8499   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8500   if (numFields && offsets[numFields] != size) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8501   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8502   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8503   for (p = 0; p < numPoints*2; p += 2) {
8504     PetscInt     o = points[p+1];
8505     PetscInt     dof, off, d;
8506     PetscScalar *varr;
8507 
8508     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8509     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8510     varr = &vArray[off];
8511     if (numFields) {
8512       PetscInt fdof, foff, fcomp, f, c;
8513 
8514       for (f = 0, foff = 0; f < numFields; ++f) {
8515         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8516         if (o >= 0) {
8517           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8518             array[offsets[f]] = varr[foff+d];
8519           }
8520         } else {
8521           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8522           for (d = fdof/fcomp-1; d >= 0; --d) {
8523             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8524               array[offsets[f]] = varr[foff+d*fcomp+c];
8525             }
8526           }
8527         }
8528         foff += fdof;
8529       }
8530     } else {
8531       if (o >= 0) {
8532         for (d = 0; d < dof; ++d, ++offsets[0]) {
8533           array[offsets[0]] = varr[d];
8534         }
8535       } else {
8536         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8537           array[offsets[0]] = varr[d];
8538         }
8539       }
8540     }
8541   }
8542   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8543   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8544   if (csize) *csize = size;
8545   *values = array;
8546   PetscFunctionReturn(0);
8547 }
8548 
8549 #undef __FUNCT__
8550 #define __FUNCT__ "DMPlexVecRestoreClosure"
8551 /*@C
8552   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8553 
8554   Not collective
8555 
8556   Input Parameters:
8557 + dm - The DM
8558 . section - The section describing the layout in v, or NULL to use the default section
8559 . v - The local vector
8560 . point - The sieve point in the DM
8561 . csize - The number of values in the closure, or NULL
8562 - values - The array of values, which is a borrowed array and should not be freed
8563 
8564   Level: intermediate
8565 
8566 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8567 @*/
8568 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8569 {
8570   PetscInt       size = 0;
8571   PetscErrorCode ierr;
8572 
8573   PetscFunctionBegin;
8574   /* Should work without recalculating size */
8575   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8576   PetscFunctionReturn(0);
8577 }
8578 
8579 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8580 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8581 
8582 #undef __FUNCT__
8583 #define __FUNCT__ "updatePoint_private"
8584 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8585 {
8586   PetscInt        cdof;   /* The number of constraints on this point */
8587   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8588   PetscScalar    *a;
8589   PetscInt        off, cind = 0, k;
8590   PetscErrorCode  ierr;
8591 
8592   PetscFunctionBegin;
8593   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8594   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8595   a    = &array[off];
8596   if (!cdof || setBC) {
8597     if (orientation >= 0) {
8598       for (k = 0; k < dof; ++k) {
8599         fuse(&a[k], values[k]);
8600       }
8601     } else {
8602       for (k = 0; k < dof; ++k) {
8603         fuse(&a[k], values[dof-k-1]);
8604       }
8605     }
8606   } else {
8607     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8608     if (orientation >= 0) {
8609       for (k = 0; k < dof; ++k) {
8610         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8611         fuse(&a[k], values[k]);
8612       }
8613     } else {
8614       for (k = 0; k < dof; ++k) {
8615         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8616         fuse(&a[k], values[dof-k-1]);
8617       }
8618     }
8619   }
8620   PetscFunctionReturn(0);
8621 }
8622 
8623 #undef __FUNCT__
8624 #define __FUNCT__ "updatePointFields_private"
8625 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8626 {
8627   PetscScalar   *a;
8628   PetscInt       numFields, off, foff, f;
8629   PetscErrorCode ierr;
8630 
8631   PetscFunctionBegin;
8632   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8633   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8634   a    = &array[off];
8635   for (f = 0, foff = 0; f < numFields; ++f) {
8636     PetscInt        fdof, fcomp, fcdof;
8637     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8638     PetscInt        cind = 0, k, c;
8639 
8640     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8641     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8642     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8643     if (!fcdof || setBC) {
8644       if (orientation >= 0) {
8645         for (k = 0; k < fdof; ++k) {
8646           fuse(&a[foff+k], values[foffs[f]+k]);
8647         }
8648       } else {
8649         for (k = fdof/fcomp-1; k >= 0; --k) {
8650           for (c = 0; c < fcomp; ++c) {
8651             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8652           }
8653         }
8654       }
8655     } else {
8656       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8657       if (orientation >= 0) {
8658         for (k = 0; k < fdof; ++k) {
8659           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8660           fuse(&a[foff+k], values[foffs[f]+k]);
8661         }
8662       } else {
8663         for (k = fdof/fcomp-1; k >= 0; --k) {
8664           for (c = 0; c < fcomp; ++c) {
8665             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8666             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8667           }
8668         }
8669       }
8670     }
8671     foff     += fdof;
8672     foffs[f] += fdof;
8673   }
8674   PetscFunctionReturn(0);
8675 }
8676 
8677 #undef __FUNCT__
8678 #define __FUNCT__ "DMPlexVecSetClosure"
8679 /*@C
8680   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8681 
8682   Not collective
8683 
8684   Input Parameters:
8685 + dm - The DM
8686 . section - The section describing the layout in v, or NULL to use the default sectionw
8687 . v - The local vector
8688 . point - The sieve point in the DM
8689 . values - The array of values, which is a borrowed array and should not be freed
8690 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8691 
8692   Level: intermediate
8693 
8694 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8695 @*/
8696 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8697 {
8698   PetscScalar   *array;
8699   PetscInt      *points = NULL;
8700   PetscInt       offsets[32];
8701   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8702   PetscErrorCode ierr;
8703 
8704   PetscFunctionBegin;
8705   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8706   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8707   if (!section) {
8708     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8709   }
8710   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8711   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8712   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8713   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8714   /* Compress out points not in the section */
8715   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8716   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8717     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8718       points[q*2]   = points[p];
8719       points[q*2+1] = points[p+1];
8720       ++q;
8721     }
8722   }
8723   numPoints = q;
8724   for (p = 0; p < numPoints*2; p += 2) {
8725     PetscInt fdof;
8726 
8727     for (f = 0; f < numFields; ++f) {
8728       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8729       offsets[f+1] += fdof;
8730     }
8731   }
8732   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8733   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8734   if (numFields) {
8735     switch (mode) {
8736     case INSERT_VALUES:
8737       for (p = 0; p < numPoints*2; p += 2) {
8738         PetscInt o = points[p+1];
8739         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8740       } break;
8741     case INSERT_ALL_VALUES:
8742       for (p = 0; p < numPoints*2; p += 2) {
8743         PetscInt o = points[p+1];
8744         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8745       } break;
8746     case ADD_VALUES:
8747       for (p = 0; p < numPoints*2; p += 2) {
8748         PetscInt o = points[p+1];
8749         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8750       } break;
8751     case ADD_ALL_VALUES:
8752       for (p = 0; p < numPoints*2; p += 2) {
8753         PetscInt o = points[p+1];
8754         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8755       } break;
8756     default:
8757       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8758     }
8759   } else {
8760     switch (mode) {
8761     case INSERT_VALUES:
8762       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8763         PetscInt o = points[p+1];
8764         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8765         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8766       } break;
8767     case INSERT_ALL_VALUES:
8768       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8769         PetscInt o = points[p+1];
8770         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8771         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8772       } break;
8773     case ADD_VALUES:
8774       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8775         PetscInt o = points[p+1];
8776         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8777         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8778       } break;
8779     case ADD_ALL_VALUES:
8780       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8781         PetscInt o = points[p+1];
8782         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8783         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8784       } break;
8785     default:
8786       SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8787     }
8788   }
8789   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8790   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8791   PetscFunctionReturn(0);
8792 }
8793 
8794 #undef __FUNCT__
8795 #define __FUNCT__ "DMPlexPrintMatSetValues"
8796 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8797 {
8798   PetscMPIInt    rank;
8799   PetscInt       i, j;
8800   PetscErrorCode ierr;
8801 
8802   PetscFunctionBegin;
8803   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr);
8804   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8805   for (i = 0; i < numIndices; i++) {
8806     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8807   }
8808   for (i = 0; i < numIndices; i++) {
8809     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8810     for (j = 0; j < numIndices; j++) {
8811 #if defined(PETSC_USE_COMPLEX)
8812       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8813 #else
8814       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8815 #endif
8816     }
8817     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8818   }
8819   PetscFunctionReturn(0);
8820 }
8821 
8822 #undef __FUNCT__
8823 #define __FUNCT__ "indicesPoint_private"
8824 /* . off - The global offset of this point */
8825 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt off, PetscInt *loff, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8826 {
8827   PetscInt        dof;    /* The number of unknowns on this point */
8828   PetscInt        cdof;   /* The number of constraints on this point */
8829   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8830   PetscInt        cind = 0, k;
8831   PetscErrorCode  ierr;
8832 
8833   PetscFunctionBegin;
8834   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8835   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8836   if (!cdof || setBC) {
8837     if (orientation >= 0) {
8838       for (k = 0; k < dof; ++k) indices[*loff+k] = off+k;
8839     } else {
8840       for (k = 0; k < dof; ++k) indices[*loff+dof-k-1] = off+k;
8841     }
8842   } else {
8843     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8844     if (orientation >= 0) {
8845       for (k = 0; k < dof; ++k) {
8846         if ((cind < cdof) && (k == cdofs[cind])) {
8847           /* Insert check for returning constrained indices */
8848           indices[*loff+k] = -(off+k+1);
8849           ++cind;
8850         } else {
8851           indices[*loff+k] = off+k-cind;
8852         }
8853       }
8854     } else {
8855       for (k = 0; k < dof; ++k) {
8856         if ((cind < cdof) && (k == cdofs[cind])) {
8857           /* Insert check for returning constrained indices */
8858           indices[*loff+dof-k-1] = -(off+k+1);
8859           ++cind;
8860         } else {
8861           indices[*loff+dof-k-1] = off+k-cind;
8862         }
8863       }
8864     }
8865   }
8866   *loff += dof;
8867   PetscFunctionReturn(0);
8868 }
8869 
8870 #undef __FUNCT__
8871 #define __FUNCT__ "indicesPointFields_private"
8872 /* . off - The global offset of this point */
8873 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8874 {
8875   PetscInt       numFields, foff, f;
8876   PetscErrorCode ierr;
8877 
8878   PetscFunctionBegin;
8879   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8880   for (f = 0, foff = 0; f < numFields; ++f) {
8881     PetscInt        fdof, fcomp, cfdof;
8882     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8883     PetscInt        cind = 0, k, c;
8884 
8885     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8886     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8887     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8888     if (!cfdof || setBC) {
8889       if (orientation >= 0) {
8890         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8891       } else {
8892         for (k = fdof/fcomp-1; k >= 0; --k) {
8893           for (c = 0; c < fcomp; ++c) {
8894             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8895           }
8896         }
8897       }
8898     } else {
8899       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8900       if (orientation >= 0) {
8901         for (k = 0; k < fdof; ++k) {
8902           if ((cind < cfdof) && (k == fcdofs[cind])) {
8903             indices[foffs[f]+k] = -(off+foff+k+1);
8904             ++cind;
8905           } else {
8906             indices[foffs[f]+k] = off+foff+k-cind;
8907           }
8908         }
8909       } else {
8910         for (k = fdof/fcomp-1; k >= 0; --k) {
8911           for (c = 0; c < fcomp; ++c) {
8912             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8913               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8914               ++cind;
8915             } else {
8916               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8917             }
8918           }
8919         }
8920       }
8921     }
8922     foff     += fdof - cfdof;
8923     foffs[f] += fdof;
8924   }
8925   PetscFunctionReturn(0);
8926 }
8927 
8928 #undef __FUNCT__
8929 #define __FUNCT__ "DMPlexMatSetClosure"
8930 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8931 {
8932   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8933   PetscInt      *points = NULL;
8934   PetscInt      *indices;
8935   PetscInt       offsets[32];
8936   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8937   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8938   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8939   PetscErrorCode ierr;
8940 
8941   PetscFunctionBegin;
8942   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8943   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8944   if (useDefault) {
8945     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8946   }
8947   if (useGlobalDefault) {
8948     if (useDefault) {
8949       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8950     } else {
8951       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8952     }
8953   }
8954   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8955   if (numFields > 31) SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8956   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8957   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8958   /* Compress out points not in the section */
8959   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8960   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8961     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8962       points[q*2]   = points[p];
8963       points[q*2+1] = points[p+1];
8964       ++q;
8965     }
8966   }
8967   numPoints = q;
8968   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8969     PetscInt fdof;
8970 
8971     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8972     for (f = 0; f < numFields; ++f) {
8973       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8974       offsets[f+1] += fdof;
8975     }
8976     numIndices += dof;
8977   }
8978   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8979 
8980   if (numFields && offsets[numFields] != numIndices) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8981   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8982   if (numFields) {
8983     for (p = 0; p < numPoints*2; p += 2) {
8984       PetscInt o = points[p+1];
8985       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8986       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8987     }
8988   } else {
8989     for (p = 0, off = 0; p < numPoints*2; p += 2) {
8990       PetscInt o = points[p+1];
8991       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8992       indicesPoint_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, &off, PETSC_FALSE, o, indices);
8993     }
8994   }
8995   if (useGlobalDefault && !useDefault) {
8996     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8997   }
8998   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8999   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9000   if (ierr) {
9001     PetscMPIInt    rank;
9002     PetscErrorCode ierr2;
9003 
9004     ierr2 = MPI_Comm_rank(PetscObjectComm((PetscObject)A), &rank);CHKERRQ(ierr2);
9005     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9006     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9007     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9008     CHKERRQ(ierr);
9009   }
9010   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9011   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9012   PetscFunctionReturn(0);
9013 }
9014 
9015 #undef __FUNCT__
9016 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9017 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9018 {
9019   PetscSection       coordSection;
9020   Vec                coordinates;
9021   const PetscScalar *coords;
9022   const PetscInt     dim = 2;
9023   PetscInt           d, f;
9024   PetscErrorCode     ierr;
9025 
9026   PetscFunctionBegin;
9027   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9028   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9029   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9030   if (v0) {
9031     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9032   }
9033   if (J) {
9034     for (d = 0; d < dim; d++) {
9035       for (f = 0; f < dim; f++) {
9036         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9037       }
9038     }
9039     *detJ = J[0]*J[3] - J[1]*J[2];
9040 #if 0
9041     if (detJ < 0.0) {
9042       const PetscReal xLength = mesh->periodicity[0];
9043 
9044       if (xLength != 0.0) {
9045         PetscReal v0x = coords[0*dim+0];
9046 
9047         if (v0x == 0.0) v0x = v0[0] = xLength;
9048         for (f = 0; f < dim; f++) {
9049           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9050 
9051           J[0*dim+f] = 0.5*(px - v0x);
9052         }
9053       }
9054       detJ = J[0]*J[3] - J[1]*J[2];
9055     }
9056 #endif
9057     PetscLogFlops(8.0 + 3.0);
9058   }
9059   if (invJ) {
9060     const PetscReal invDet = 1.0/(*detJ);
9061 
9062     invJ[0] =  invDet*J[3];
9063     invJ[1] = -invDet*J[1];
9064     invJ[2] = -invDet*J[2];
9065     invJ[3] =  invDet*J[0];
9066     PetscLogFlops(5.0);
9067   }
9068   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9069   PetscFunctionReturn(0);
9070 }
9071 
9072 #undef __FUNCT__
9073 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9074 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9075 {
9076   PetscSection       coordSection;
9077   Vec                coordinates;
9078   const PetscScalar *coords;
9079   const PetscInt     dim = 2;
9080   PetscInt           d, f;
9081   PetscErrorCode     ierr;
9082 
9083   PetscFunctionBegin;
9084   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9085   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9086   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9087   if (v0) {
9088     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9089   }
9090   if (J) {
9091     for (d = 0; d < dim; d++) {
9092       for (f = 0; f < dim; f++) {
9093         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9094       }
9095     }
9096     *detJ = J[0]*J[3] - J[1]*J[2];
9097     PetscLogFlops(8.0 + 3.0);
9098   }
9099   if (invJ) {
9100     const PetscReal invDet = 1.0/(*detJ);
9101 
9102     invJ[0] =  invDet*J[3];
9103     invJ[1] = -invDet*J[1];
9104     invJ[2] = -invDet*J[2];
9105     invJ[3] =  invDet*J[0];
9106     PetscLogFlops(5.0);
9107   }
9108   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9109   PetscFunctionReturn(0);
9110 }
9111 
9112 #undef __FUNCT__
9113 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9114 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9115 {
9116   PetscSection       coordSection;
9117   Vec                coordinates;
9118   const PetscScalar *coords;
9119   const PetscInt     dim = 3;
9120   PetscInt           d, f;
9121   PetscErrorCode     ierr;
9122 
9123   PetscFunctionBegin;
9124   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9125   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9126   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9127   if (v0) {
9128     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9129   }
9130   if (J) {
9131     for (d = 0; d < dim; d++) {
9132       for (f = 0; f < dim; f++) {
9133         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9134       }
9135     }
9136     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9137     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9138              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9139              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9140     PetscLogFlops(18.0 + 12.0);
9141   }
9142   if (invJ) {
9143     const PetscReal invDet = 1.0/(*detJ);
9144 
9145     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9146     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9147     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9148     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9149     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9150     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9151     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9152     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9153     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9154     PetscLogFlops(37.0);
9155   }
9156   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9157   PetscFunctionReturn(0);
9158 }
9159 
9160 #undef __FUNCT__
9161 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9162 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9163 {
9164   PetscSection       coordSection;
9165   Vec                coordinates;
9166   const PetscScalar *coords;
9167   const PetscInt     dim = 3;
9168   PetscInt           d;
9169   PetscErrorCode     ierr;
9170 
9171   PetscFunctionBegin;
9172   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9173   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9174   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9175   if (v0) {
9176     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9177   }
9178   if (J) {
9179     for (d = 0; d < dim; d++) {
9180       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9181       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9182       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9183     }
9184     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9185              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9186              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9187     PetscLogFlops(18.0 + 12.0);
9188   }
9189   if (invJ) {
9190     const PetscReal invDet = -1.0/(*detJ);
9191 
9192     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9193     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9194     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9195     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9196     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9197     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9198     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9199     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9200     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9201     PetscLogFlops(37.0);
9202   }
9203   *detJ *= 8.0;
9204   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, NULL, &coords);CHKERRQ(ierr);
9205   PetscFunctionReturn(0);
9206 }
9207 
9208 #undef __FUNCT__
9209 #define __FUNCT__ "DMPlexComputeCellGeometry"
9210 /*@C
9211   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9212 
9213   Collective on DM
9214 
9215   Input Arguments:
9216 + dm   - the DM
9217 - cell - the cell
9218 
9219   Output Arguments:
9220 + v0   - the translation part of this affine transform
9221 . J    - the Jacobian of the transform to the reference element
9222 . invJ - the inverse of the Jacobian
9223 - detJ - the Jacobian determinant
9224 
9225   Level: advanced
9226 
9227 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9228 @*/
9229 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9230 {
9231   PetscInt       dim, coneSize;
9232   PetscErrorCode ierr;
9233 
9234   PetscFunctionBegin;
9235   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9236   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9237   switch (dim) {
9238   case 2:
9239     switch (coneSize) {
9240     case 3:
9241       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9242       break;
9243     case 4:
9244       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9245       break;
9246     default:
9247       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9248     }
9249     break;
9250   case 3:
9251     switch (coneSize) {
9252     case 4:
9253       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9254       break;
9255     case 8:
9256       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9257       break;
9258     default:
9259       SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9260     }
9261     break;
9262   default:
9263     SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9264   }
9265   PetscFunctionReturn(0);
9266 }
9267 
9268 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9269 {
9270   switch (i) {
9271   case 0:
9272     switch (j) {
9273     case 0: return 0;
9274     case 1:
9275       switch (k) {
9276       case 0: return 0;
9277       case 1: return 0;
9278       case 2: return 1;
9279       }
9280     case 2:
9281       switch (k) {
9282       case 0: return 0;
9283       case 1: return -1;
9284       case 2: return 0;
9285       }
9286     }
9287   case 1:
9288     switch (j) {
9289     case 0:
9290       switch (k) {
9291       case 0: return 0;
9292       case 1: return 0;
9293       case 2: return -1;
9294       }
9295     case 1: return 0;
9296     case 2:
9297       switch (k) {
9298       case 0: return 1;
9299       case 1: return 0;
9300       case 2: return 0;
9301       }
9302     }
9303   case 2:
9304     switch (j) {
9305     case 0:
9306       switch (k) {
9307       case 0: return 0;
9308       case 1: return 1;
9309       case 2: return 0;
9310       }
9311     case 1:
9312       switch (k) {
9313       case 0: return -1;
9314       case 1: return 0;
9315       case 2: return 0;
9316       }
9317     case 2: return 0;
9318     }
9319   }
9320   return 0;
9321 }
9322 
9323 #undef __FUNCT__
9324 #define __FUNCT__ "DMPlexCreateRigidBody"
9325 /*@C
9326   DMPlexCreateRigidBody - create rigid body modes from coordinates
9327 
9328   Collective on DM
9329 
9330   Input Arguments:
9331 + dm - the DM
9332 . section - the local section associated with the rigid field, or NULL for the default section
9333 - globalSection - the global section associated with the rigid field, or NULL for the default section
9334 
9335   Output Argument:
9336 . sp - the null space
9337 
9338   Note: This is necessary to take account of Dirichlet conditions on the displacements
9339 
9340   Level: advanced
9341 
9342 .seealso: MatNullSpaceCreate()
9343 @*/
9344 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9345 {
9346   MPI_Comm       comm;
9347   Vec            coordinates, localMode, mode[6];
9348   PetscSection   coordSection;
9349   PetscScalar   *coords;
9350   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9351   PetscErrorCode ierr;
9352 
9353   PetscFunctionBegin;
9354   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
9355   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9356   if (dim == 1) {
9357     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, NULL, sp);CHKERRQ(ierr);
9358     PetscFunctionReturn(0);
9359   }
9360   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9361   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9362   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9363   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9364   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9365   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9366   m    = (dim*(dim+1))/2;
9367   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9368   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9369   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9370   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9371   /* Assume P1 */
9372   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9373   for (d = 0; d < dim; ++d) {
9374     PetscScalar values[3] = {0.0, 0.0, 0.0};
9375 
9376     values[d] = 1.0;
9377     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9378     for (v = vStart; v < vEnd; ++v) {
9379       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9380     }
9381     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9382     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9383   }
9384   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9385   for (d = dim; d < dim*(dim+1)/2; ++d) {
9386     PetscInt i, j, k = dim > 2 ? d - dim : d;
9387 
9388     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9389     for (v = vStart; v < vEnd; ++v) {
9390       PetscScalar values[3] = {0.0, 0.0, 0.0};
9391       PetscInt    off;
9392 
9393       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9394       for (i = 0; i < dim; ++i) {
9395         for (j = 0; j < dim; ++j) {
9396           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9397         }
9398       }
9399       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9400     }
9401     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9402     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9403   }
9404   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9405   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9406   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);}
9407   /* Orthonormalize system */
9408   for (i = dim; i < m; ++i) {
9409     PetscScalar dots[6];
9410 
9411     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9412     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9413     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9414     ierr = VecNormalize(mode[i], NULL);CHKERRQ(ierr);
9415   }
9416   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9417   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9418   PetscFunctionReturn(0);
9419 }
9420 
9421 #undef __FUNCT__
9422 #define __FUNCT__ "DMPlexGetHybridBounds"
9423 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9424 {
9425   DM_Plex       *mesh = (DM_Plex*) dm->data;
9426   PetscInt       dim;
9427   PetscErrorCode ierr;
9428 
9429   PetscFunctionBegin;
9430   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9431   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9432   if (cMax) *cMax = mesh->hybridPointMax[dim];
9433   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9434   if (eMax) *eMax = mesh->hybridPointMax[1];
9435   if (vMax) *vMax = mesh->hybridPointMax[0];
9436   PetscFunctionReturn(0);
9437 }
9438 
9439 #undef __FUNCT__
9440 #define __FUNCT__ "DMPlexSetHybridBounds"
9441 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9442 {
9443   DM_Plex       *mesh = (DM_Plex*) dm->data;
9444   PetscInt       dim;
9445   PetscErrorCode ierr;
9446 
9447   PetscFunctionBegin;
9448   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9449   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9450   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9451   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9452   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9453   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9454   PetscFunctionReturn(0);
9455 }
9456 
9457 #undef __FUNCT__
9458 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9459 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9460 {
9461   DM_Plex *mesh = (DM_Plex*) dm->data;
9462 
9463   PetscFunctionBegin;
9464   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9465   PetscValidPointer(cellHeight, 2);
9466   *cellHeight = mesh->vtkCellHeight;
9467   PetscFunctionReturn(0);
9468 }
9469 
9470 #undef __FUNCT__
9471 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9472 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9473 {
9474   DM_Plex *mesh = (DM_Plex*) dm->data;
9475 
9476   PetscFunctionBegin;
9477   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9478   mesh->vtkCellHeight = cellHeight;
9479   PetscFunctionReturn(0);
9480 }
9481 
9482 #undef __FUNCT__
9483 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9484 /* We can easily have a form that takes an IS instead */
9485 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9486 {
9487   PetscSection   section, globalSection;
9488   PetscInt      *numbers, p;
9489   PetscErrorCode ierr;
9490 
9491   PetscFunctionBegin;
9492   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm), &section);CHKERRQ(ierr);
9493   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9494   for (p = pStart; p < pEnd; ++p) {
9495     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9496   }
9497   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9498   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9499   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9500   for (p = pStart; p < pEnd; ++p) {
9501     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9502   }
9503   ierr = ISCreateGeneral(PetscObjectComm((PetscObject)dm), pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9504   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9505   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9506   PetscFunctionReturn(0);
9507 }
9508 
9509 #undef __FUNCT__
9510 #define __FUNCT__ "DMPlexGetCellNumbering"
9511 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9512 {
9513   DM_Plex       *mesh = (DM_Plex*) dm->data;
9514   PetscInt       cellHeight, cStart, cEnd, cMax;
9515   PetscErrorCode ierr;
9516 
9517   PetscFunctionBegin;
9518   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9519   if (!mesh->globalCellNumbers) {
9520     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9521     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9522     ierr = DMPlexGetHybridBounds(dm, &cMax, NULL, NULL, NULL);CHKERRQ(ierr);
9523     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9524     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9525   }
9526   *globalCellNumbers = mesh->globalCellNumbers;
9527   PetscFunctionReturn(0);
9528 }
9529 
9530 #undef __FUNCT__
9531 #define __FUNCT__ "DMPlexGetVertexNumbering"
9532 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9533 {
9534   DM_Plex       *mesh = (DM_Plex*) dm->data;
9535   PetscInt       vStart, vEnd, vMax;
9536   PetscErrorCode ierr;
9537 
9538   PetscFunctionBegin;
9539   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9540   if (!mesh->globalVertexNumbers) {
9541     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9542     ierr = DMPlexGetHybridBounds(dm, NULL, NULL, NULL, &vMax);CHKERRQ(ierr);
9543     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9544     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9545   }
9546   *globalVertexNumbers = mesh->globalVertexNumbers;
9547   PetscFunctionReturn(0);
9548 }
9549 
9550 #undef __FUNCT__
9551 #define __FUNCT__ "DMPlexGetScale"
9552 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9553 {
9554   DM_Plex *mesh = (DM_Plex*) dm->data;
9555 
9556   PetscFunctionBegin;
9557   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9558   PetscValidPointer(scale, 3);
9559   *scale = mesh->scale[unit];
9560   PetscFunctionReturn(0);
9561 }
9562 
9563 #undef __FUNCT__
9564 #define __FUNCT__ "DMPlexSetScale"
9565 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9566 {
9567   DM_Plex *mesh = (DM_Plex*) dm->data;
9568 
9569   PetscFunctionBegin;
9570   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9571   mesh->scale[unit] = scale;
9572   PetscFunctionReturn(0);
9573 }
9574 
9575 
9576 /*******************************************************************************
9577 This should be in a separate Discretization object, but I am not sure how to lay
9578 it out yet, so I am stuffing things here while I experiment.
9579 *******************************************************************************/
9580 #undef __FUNCT__
9581 #define __FUNCT__ "DMPlexSetFEMIntegration"
9582 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9583                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9584                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9585                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9586                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9587                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9588                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9589                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9590                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9591                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9592                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9593                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9594                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9595                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9596                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9597                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9598                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9599 {
9600   DM_Plex *mesh = (DM_Plex*) dm->data;
9601 
9602   PetscFunctionBegin;
9603   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9604   mesh->integrateResidualFEM       = integrateResidualFEM;
9605   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9606   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9607   PetscFunctionReturn(0);
9608 }
9609 
9610 #undef __FUNCT__
9611 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9612 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9613 {
9614   Vec            coordinates;
9615   PetscSection   section, cSection;
9616   PetscInt       dim, vStart, vEnd, v, c, d;
9617   PetscScalar   *values, *cArray;
9618   PetscReal     *coords;
9619   PetscErrorCode ierr;
9620 
9621   PetscFunctionBegin;
9622   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9623   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9624   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9625   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9626   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9627   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9628   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9629   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9630   for (v = vStart; v < vEnd; ++v) {
9631     PetscInt dof, off;
9632 
9633     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9634     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9635     if (dof > dim) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9636     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
9637     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9638     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9639   }
9640   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9641   /* Temporary, must be replaced by a projection on the finite element basis */
9642   {
9643     PetscInt eStart = 0, eEnd = 0, e, depth;
9644 
9645     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9646     --depth;
9647     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9648     for (e = eStart; e < eEnd; ++e) {
9649       const PetscInt *cone = NULL;
9650       PetscInt        coneSize, d;
9651       PetscScalar    *coordsA, *coordsB;
9652 
9653       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9654       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9655       if (coneSize != 2) SETERRQ2(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9656       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9657       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9658       for (d = 0; d < dim; ++d) {
9659         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9660       }
9661       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
9662       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9663     }
9664   }
9665 
9666   ierr = PetscFree(coords);CHKERRQ(ierr);
9667   ierr = PetscFree(values);CHKERRQ(ierr);
9668 #if 0
9669   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9670   PetscReal      detJ;
9671 
9672   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9673   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9674   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
9675 
9676   for (PetscInt c = cStart; c < cEnd; ++c) {
9677     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9678     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9679     const int                          oSize   = pV.getSize();
9680     int                                v       = 0;
9681 
9682     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, NULL, &detJ);CHKERRQ(ierr);
9683     for (PetscInt cl = 0; cl < oSize; ++cl) {
9684       const PetscInt fDim;
9685 
9686       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9687       if (pointDim) {
9688         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9689           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9690         }
9691       }
9692     }
9693     ierr = DMPlexVecSetClosure(dm, NULL, localX, c, values);CHKERRQ(ierr);
9694     pV.clear();
9695   }
9696   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9697   ierr = PetscFree(values);CHKERRQ(ierr);
9698 #endif
9699   PetscFunctionReturn(0);
9700 }
9701 
9702 #undef __FUNCT__
9703 #define __FUNCT__ "DMPlexProjectFunction"
9704 /*@C
9705   DMPlexProjectFunction - This projects the given function into the function space provided.
9706 
9707   Input Parameters:
9708 + dm      - The DM
9709 . numComp - The number of components (functions)
9710 . funcs   - The coordinate functions to evaluate
9711 - mode    - The insertion mode for values
9712 
9713   Output Parameter:
9714 . X - vector
9715 
9716   Level: developer
9717 
9718   Note:
9719   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9720   We will eventually fix it.
9721 
9722 ,seealso: DMPlexComputeL2Diff()
9723 */
9724 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9725 {
9726   Vec            localX;
9727   PetscErrorCode ierr;
9728 
9729   PetscFunctionBegin;
9730   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9731   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9732   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9733   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9734   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9735   PetscFunctionReturn(0);
9736 }
9737 
9738 #undef __FUNCT__
9739 #define __FUNCT__ "DMPlexComputeL2Diff"
9740 /*@C
9741   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9742 
9743   Input Parameters:
9744 + dm    - The DM
9745 . quad  - The PetscQuadrature object for each field
9746 . funcs - The functions to evaluate for each field component
9747 - X     - The coefficient vector u_h
9748 
9749   Output Parameter:
9750 . diff - The diff ||u - u_h||_2
9751 
9752   Level: developer
9753 
9754 .seealso: DMPlexProjectFunction()
9755 */
9756 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
9757 {
9758   const PetscInt debug = 0;
9759   PetscSection   section;
9760   Vec            localX;
9761   PetscReal     *coords, *v0, *J, *invJ, detJ;
9762   PetscReal      localDiff = 0.0;
9763   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9764   PetscErrorCode ierr;
9765 
9766   PetscFunctionBegin;
9767   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9768   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9769   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9770   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9771   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9772   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9773   for (field = 0; field < numFields; ++field) {
9774     numComponents += quad[field].numComponents;
9775   }
9776   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9777   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9778   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9779   for (c = cStart; c < cEnd; ++c) {
9780     const PetscScalar *x;
9781     PetscReal          elemDiff = 0.0;
9782 
9783     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9784     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9785     ierr = DMPlexVecGetClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9786 
9787     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9788       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9789       const PetscReal *quadPoints    = quad[field].quadPoints;
9790       const PetscReal *quadWeights   = quad[field].quadWeights;
9791       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9792       const PetscInt   numBasisComps = quad[field].numComponents;
9793       const PetscReal *basis         = quad[field].basis;
9794       PetscInt         q, d, e, fc, f;
9795 
9796       if (debug) {
9797         char title[1024];
9798         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9799         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9800       }
9801       for (q = 0; q < numQuadPoints; ++q) {
9802         for (d = 0; d < dim; d++) {
9803           coords[d] = v0[d];
9804           for (e = 0; e < dim; e++) {
9805             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9806           }
9807         }
9808         for (fc = 0; fc < numBasisComps; ++fc) {
9809           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9810           PetscReal       interpolant = 0.0;
9811           for (f = 0; f < numBasisFuncs; ++f) {
9812             const PetscInt fidx = f*numBasisComps+fc;
9813             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9814           }
9815           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9816           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9817         }
9818       }
9819       comp        += numBasisComps;
9820       fieldOffset += numBasisFuncs*numBasisComps;
9821     }
9822     ierr = DMPlexVecRestoreClosure(dm, NULL, localX, c, NULL, &x);CHKERRQ(ierr);
9823     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9824     localDiff += elemDiff;
9825   }
9826   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9827   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9828   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9829   *diff = PetscSqrtReal(*diff);
9830   PetscFunctionReturn(0);
9831 }
9832 
9833 #undef __FUNCT__
9834 #define __FUNCT__ "DMPlexComputeResidualFEM"
9835 /*@
9836   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9837 
9838   Input Parameters:
9839 + dm - The mesh
9840 . X  - Local input vector
9841 - user - The user context
9842 
9843   Output Parameter:
9844 . F  - Local output vector
9845 
9846   Note:
9847   The second member of the user context must be an FEMContext.
9848 
9849   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9850   like a GPU, or vectorize on a multicore machine.
9851 
9852 .seealso: DMPlexComputeJacobianActionFEM()
9853 */
9854 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9855 {
9856   DM_Plex         *mesh = (DM_Plex*) dm->data;
9857   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9858   PetscQuadrature *quad = fem->quad;
9859   PetscSection     section;
9860   PetscReal       *v0, *J, *invJ, *detJ;
9861   PetscScalar     *elemVec, *u;
9862   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9863   PetscInt         cellDof = 0, numComponents = 0;
9864   PetscErrorCode   ierr;
9865 
9866   PetscFunctionBegin;
9867   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9868   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9869   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9870   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9871   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9872   numCells = cEnd - cStart;
9873   for (field = 0; field < numFields; ++field) {
9874     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
9875     numComponents += quad[field].numComponents;
9876   }
9877   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9878   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9879   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
9880   for (c = cStart; c < cEnd; ++c) {
9881     const PetscScalar *x;
9882     PetscInt           i;
9883 
9884     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9885     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9886     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9887 
9888     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9889     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9890   }
9891   for (field = 0; field < numFields; ++field) {
9892     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9893     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9894     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9895     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9896     /* Conforming batches */
9897     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9898     PetscInt numBlocks  = 1;
9899     PetscInt batchSize  = numBlocks * blockSize;
9900     PetscInt numBatches = numBatchesTmp;
9901     PetscInt numChunks  = numCells / (numBatches*batchSize);
9902     /* Remainder */
9903     PetscInt numRemainder = numCells % (numBatches * batchSize);
9904     PetscInt offset       = numCells - numRemainder;
9905 
9906     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9907     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9908                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9909   }
9910   for (c = cStart; c < cEnd; ++c) {
9911     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9912     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9913   }
9914   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9915   if (mesh->printFEM) {
9916     PetscMPIInt rank, numProcs;
9917     PetscInt    p;
9918 
9919     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
9920     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
9921     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9922     for (p = 0; p < numProcs; ++p) {
9923       if (p == rank) {
9924         Vec f;
9925 
9926         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9927         ierr = VecCopy(F, f);CHKERRQ(ierr);
9928         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9929         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9930         ierr = VecDestroy(&f);CHKERRQ(ierr);
9931         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9932       }
9933       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9934     }
9935   }
9936   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9937   PetscFunctionReturn(0);
9938 }
9939 
9940 #undef __FUNCT__
9941 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9942 /*@C
9943   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9944 
9945   Input Parameters:
9946 + dm - The mesh
9947 . J  - The Jacobian shell matrix
9948 . X  - Local input vector
9949 - user - The user context
9950 
9951   Output Parameter:
9952 . F  - Local output vector
9953 
9954   Note:
9955   The second member of the user context must be an FEMContext.
9956 
9957   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9958   like a GPU, or vectorize on a multicore machine.
9959 
9960 .seealso: DMPlexComputeResidualFEM()
9961 */
9962 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9963 {
9964   DM_Plex         *mesh = (DM_Plex*) dm->data;
9965   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
9966   PetscQuadrature *quad = fem->quad;
9967   PetscSection     section;
9968   JacActionCtx    *jctx;
9969   PetscReal       *v0, *J, *invJ, *detJ;
9970   PetscScalar     *elemVec, *u, *a;
9971   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9972   PetscInt         cellDof = 0;
9973   PetscErrorCode   ierr;
9974 
9975   PetscFunctionBegin;
9976   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9977   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9978   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9979   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9980   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9981   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9982   numCells = cEnd - cStart;
9983   for (field = 0; field < numFields; ++field) {
9984     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9985   }
9986   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9987   ierr = PetscMalloc7(numCells*cellDof,PetscScalar,&u,numCells*cellDof,PetscScalar,&a,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
9988   for (c = cStart; c < cEnd; ++c) {
9989     const PetscScalar *x;
9990     PetscInt           i;
9991 
9992     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9993     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9994     ierr = DMPlexVecGetClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9995     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
9996     ierr = DMPlexVecRestoreClosure(dm, NULL, jctx->u, c, NULL, &x);CHKERRQ(ierr);
9997     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
9998     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
9999     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10000   }
10001   for (field = 0; field < numFields; ++field) {
10002     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10003     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10004     /* Conforming batches */
10005     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10006     PetscInt numBlocks  = 1;
10007     PetscInt batchSize  = numBlocks * blockSize;
10008     PetscInt numBatches = numBatchesTmp;
10009     PetscInt numChunks  = numCells / (numBatches*batchSize);
10010     /* Remainder */
10011     PetscInt numRemainder = numCells % (numBatches * batchSize);
10012     PetscInt offset       = numCells - numRemainder;
10013 
10014     ierr = (*mesh->integrateJacobianActionFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, a, v0, J, invJ, detJ, fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, elemVec);CHKERRQ(ierr);
10015     ierr = (*mesh->integrateJacobianActionFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &a[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10016                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10017   }
10018   for (c = cStart; c < cEnd; ++c) {
10019     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10020     ierr = DMPlexVecSetClosure(dm, NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10021   }
10022   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10023   if (mesh->printFEM) {
10024     PetscMPIInt rank, numProcs;
10025     PetscInt    p;
10026 
10027     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank);CHKERRQ(ierr);
10028     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm), &numProcs);CHKERRQ(ierr);
10029     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10030     for (p = 0; p < numProcs; ++p) {
10031       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10032       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10033     }
10034   }
10035   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10036   PetscFunctionReturn(0);
10037 }
10038 
10039 #undef __FUNCT__
10040 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10041 /*@
10042   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10043 
10044   Input Parameters:
10045 + dm - The mesh
10046 . X  - Local input vector
10047 - user - The user context
10048 
10049   Output Parameter:
10050 . Jac  - Jacobian matrix
10051 
10052   Note:
10053   The second member of the user context must be an FEMContext.
10054 
10055   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10056   like a GPU, or vectorize on a multicore machine.
10057 
10058 .seealso: FormFunctionLocal()
10059 */
10060 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10061 {
10062   DM_Plex         *mesh = (DM_Plex*) dm->data;
10063   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10064   PetscQuadrature *quad = fem->quad;
10065   PetscSection     section;
10066   PetscReal       *v0, *J, *invJ, *detJ;
10067   PetscScalar     *elemMat, *u;
10068   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10069   PetscInt         cellDof = 0, numComponents = 0;
10070   PetscBool        isShell;
10071   PetscErrorCode   ierr;
10072 
10073   PetscFunctionBegin;
10074   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10075   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10076   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10077   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10078   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10079   numCells = cEnd - cStart;
10080   for (field = 0; field < numFields; ++field) {
10081     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10082     numComponents += quad[field].numComponents;
10083   }
10084   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10085   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10086   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof*cellDof,PetscScalar,&elemMat);CHKERRQ(ierr);
10087   for (c = cStart; c < cEnd; ++c) {
10088     const PetscScalar *x;
10089     PetscInt           i;
10090 
10091     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10092     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10093     ierr = DMPlexVecGetClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10094 
10095     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10096     ierr = DMPlexVecRestoreClosure(dm, NULL, X, c, NULL, &x);CHKERRQ(ierr);
10097   }
10098   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10099   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10100     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10101     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10102     PetscInt       fieldJ;
10103 
10104     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10105       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10106       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10107       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10108       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10109       /* Conforming batches */
10110       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10111       PetscInt numBlocks  = 1;
10112       PetscInt batchSize  = numBlocks * blockSize;
10113       PetscInt numBatches = numBatchesTmp;
10114       PetscInt numChunks  = numCells / (numBatches*batchSize);
10115       /* Remainder */
10116       PetscInt numRemainder = numCells % (numBatches * batchSize);
10117       PetscInt offset       = numCells - numRemainder;
10118 
10119       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10120       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10121                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10122     }
10123   }
10124   for (c = cStart; c < cEnd; ++c) {
10125     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10126     ierr = DMPlexMatSetClosure(dm, NULL, NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10127   }
10128   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10129 
10130   /* Assemble matrix, using the 2-step process:
10131        MatAssemblyBegin(), MatAssemblyEnd(). */
10132   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10133   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10134 
10135   if (mesh->printFEM) {
10136     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10137     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10138     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10139   }
10140   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10141   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10142   if (isShell) {
10143     JacActionCtx *jctx;
10144 
10145     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10146     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10147   }
10148   *str = SAME_NONZERO_PATTERN;
10149   PetscFunctionReturn(0);
10150 }
10151 
10152 
10153 #undef __FUNCT__
10154 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10155 /*@C
10156   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10157   the local section and an SF describing the section point overlap.
10158 
10159   Input Parameters:
10160   + s - The PetscSection for the local field layout
10161   . sf - The SF describing parallel layout of the section points
10162   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10163   . label - The label specifying the points
10164   - labelValue - The label stratum specifying the points
10165 
10166   Output Parameter:
10167   . gsection - The PetscSection for the global field layout
10168 
10169   Note: This gives negative sizes and offsets to points not owned by this process
10170 
10171   Level: developer
10172 
10173 .seealso: PetscSectionCreate()
10174 @*/
10175 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
10176 {
10177   PetscInt      *neg;
10178   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
10179   PetscErrorCode ierr;
10180 
10181   PetscFunctionBegin;
10182   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
10183   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
10184   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
10185   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
10186   /* Mark ghost points with negative dof */
10187   for (p = pStart; p < pEnd; ++p) {
10188     PetscInt value;
10189 
10190     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
10191     if (value != labelValue) continue;
10192     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
10193     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
10194     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
10195     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
10196     neg[p-pStart] = -(dof+1);
10197   }
10198   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
10199   ierr = PetscSFGetGraph(sf, &nroots, NULL, NULL, NULL);CHKERRQ(ierr);
10200   if (nroots >= 0) {
10201     if (nroots > pEnd - pStart) {
10202       PetscInt *tmpDof;
10203       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10204       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
10205       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10206       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
10207       for (p = pStart; p < pEnd; ++p) {
10208         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
10209       }
10210       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
10211     } else {
10212       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10213       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
10214     }
10215   }
10216   /* Calculate new sizes, get proccess offset, and calculate point offsets */
10217   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10218     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
10219 
10220     (*gsection)->atlasOff[p] = off;
10221 
10222     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
10223   }
10224   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
10225   globalOff -= off;
10226   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
10227     (*gsection)->atlasOff[p] += globalOff;
10228 
10229     neg[p] = -((*gsection)->atlasOff[p]+1);
10230   }
10231   /* Put in negative offsets for ghost points */
10232   if (nroots >= 0) {
10233     if (nroots > pEnd - pStart) {
10234       PetscInt *tmpOff;
10235       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
10236       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
10237       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10238       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
10239       for (p = pStart; p < pEnd; ++p) {
10240         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
10241       }
10242       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
10243     } else {
10244       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10245       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
10246     }
10247   }
10248   ierr = PetscFree(neg);CHKERRQ(ierr);
10249   PetscFunctionReturn(0);
10250 }
10251