xref: /petsc/src/dm/impls/plex/plex.c (revision 2205254efee3a00a594e5e2a3a70f74dcb40bc03)
1 #include <petsc-private/pleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 
4 /* Logging support */
5 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
6 
7 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
8 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "VecView_Plex_Local"
12 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
13 {
14   DM             dm;
15   PetscBool      isvtk;
16   PetscErrorCode ierr;
17 
18   PetscFunctionBegin;
19   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
20   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
21   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
22   if (isvtk) {
23     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
24     PetscSection            section;
25     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
26 
27     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
28     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
29     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, PETSC_NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, PETSC_NULL);CHKERRQ(ierr);
32     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
33     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
34     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
35     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
36     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
37     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
38       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
39     } else if (cdof && vdof) {
40       SETERRQ(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
41     } else if (cdof) {
42       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
43        * vector or just happens to have the same number of dofs as the dimension. */
44       if (cdof == dim) {
45         ft = PETSC_VTK_CELL_VECTOR_FIELD;
46       } else {
47         ft = PETSC_VTK_CELL_FIELD;
48       }
49     } else if (vdof) {
50       if (vdof == dim) {
51         ft = PETSC_VTK_POINT_VECTOR_FIELD;
52       } else {
53         ft = PETSC_VTK_POINT_FIELD;
54       }
55     } else SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
56 
57     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
58     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
59     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
60   } else {
61     PetscBool isseq;
62 
63     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
64     if (isseq) {
65       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
66     } else {
67       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "VecView_Plex"
75 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
76 {
77   DM             dm;
78   PetscBool      isvtk;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
83   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
84   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
85   if (isvtk) {
86     Vec         locv;
87     const char *name;
88 
89     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
90     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
91     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
92     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
95     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
96   } else {
97     PetscBool isseq;
98 
99     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
100     if (isseq) {
101       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
102     } else {
103       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
104     }
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "DMPlexView_Ascii"
111 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
112 {
113   DM_Plex          *mesh = (DM_Plex*) dm->data;
114   DM                cdm;
115   DMLabel           markers;
116   PetscSection      coordSection;
117   Vec               coordinates;
118   PetscViewerFormat format;
119   PetscErrorCode    ierr;
120 
121   PetscFunctionBegin;
122   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
123   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
124   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
125   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
126   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
127     const char *name;
128     PetscInt    maxConeSize, maxSupportSize;
129     PetscInt    pStart, pEnd, p;
130     PetscMPIInt rank, size;
131 
132     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
133     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
134     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
135     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
136     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
137     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
138     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
142     for (p = pStart; p < pEnd; ++p) {
143       PetscInt dof, off, s;
144 
145       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
146       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
147       for (s = off; s < off+dof; ++s) {
148         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
149       }
150     }
151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
152     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
153     for (p = pStart; p < pEnd; ++p) {
154       PetscInt dof, off, c;
155 
156       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
157       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
158       for (c = off; c < off+dof; ++c) {
159         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
160       }
161     }
162     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
163     ierr = PetscSectionGetChart(coordSection, &pStart, PETSC_NULL);CHKERRQ(ierr);
164     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
165     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
166     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
167     if (size > 1) {
168       PetscSF sf;
169 
170       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
171       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
172     }
173     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
174   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
175     const char  *name;
176     const char  *colors[3] = {"red", "blue", "green"};
177     const int    numColors  = 3;
178     PetscReal    scale      = 2.0;
179     PetscScalar *coords;
180     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
181     PetscMPIInt  rank, size;
182 
183     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
184     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
185     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
186     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
187     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
188     ierr = PetscViewerASCIIPrintf(viewer, "\
189 \\documentclass[crop,multi=false]{standalone}\n\n\
190 \\usepackage{tikz}\n\
191 \\usepackage{pgflibraryshapes}\n\
192 \\usetikzlibrary{backgrounds}\n\
193 \\usetikzlibrary{arrows}\n\
194 \\begin{document}\n\
195 \\section{%s}\n\
196 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
197     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
198     for (p = 0; p < size; ++p) {
199       if (p > 0 && p == size-1) {
200         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
201       } else if (p > 0) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
203       }
204       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
205     }
206     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
207 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
208     /* Plot vertices */
209     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
210     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
211     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
212     for (v = vStart; v < vEnd; ++v) {
213       PetscInt off, dof, d;
214 
215       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
216       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
217       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
218       for (d = 0; d < dof; ++d) {
219         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
220         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
221       }
222       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
223     }
224     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
225     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
226     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
227     /* Plot edges */
228     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
229     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
230     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
231     for (e = eStart; e < eEnd; ++e) {
232       const PetscInt *cone;
233       PetscInt        coneSize, offA, offB, dof, d;
234 
235       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
236       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
237       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
238       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
239       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
240       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
241       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
242       for (d = 0; d < dof; ++d) {
243         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
244         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
245       }
246       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
247     }
248     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
249     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
250     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
251     /* Plot cells */
252     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
253     for (c = cStart; c < cEnd; ++c) {
254       PetscInt *closure = PETSC_NULL;
255       PetscInt  closureSize, firstPoint = -1;
256 
257       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
258       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
259       for (p = 0; p < closureSize*2; p += 2) {
260         const PetscInt point = closure[p];
261 
262         if ((point < vStart) || (point >= vEnd)) continue;
263         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
264         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
265         if (firstPoint < 0) firstPoint = point;
266       }
267       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
268       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
269       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
270     }
271     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
272     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
273     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
274   } else {
275     MPI_Comm    comm = ((PetscObject) dm)->comm;
276     PetscInt   *sizes;
277     PetscInt    locDepth, depth, dim, d;
278     PetscInt    pStart, pEnd, p;
279     PetscMPIInt size;
280 
281     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
282     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
283     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
284     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
285     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
286     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
287     if (depth == 1) {
288       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
289       pEnd = pEnd - pStart;
290       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
291       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
292       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
293       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
294       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
295       pEnd = pEnd - pStart;
296       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
297       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
298       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
299       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
300     } else {
301       for (d = 0; d <= dim; d++) {
302         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
303         pEnd = pEnd - pStart;
304         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
305         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
306         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
307         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
308       }
309     }
310     ierr = PetscFree(sizes);CHKERRQ(ierr);
311   }
312   PetscFunctionReturn(0);
313 }
314 
315 #undef __FUNCT__
316 #define __FUNCT__ "DMView_Plex"
317 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
318 {
319   PetscBool      iascii, isbinary;
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
324   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
325   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
326   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
327   if (iascii) {
328     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
329 #if 0
330   } else if (isbinary) {
331     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
332 #endif
333   }
334   PetscFunctionReturn(0);
335 }
336 
337 #undef __FUNCT__
338 #define __FUNCT__ "DMDestroy_Plex"
339 PetscErrorCode DMDestroy_Plex(DM dm)
340 {
341   DM_Plex       *mesh = (DM_Plex*) dm->data;
342   DMLabel        next  = mesh->labels;
343   PetscErrorCode ierr;
344 
345   PetscFunctionBegin;
346   if (--mesh->refct > 0) PetscFunctionReturn(0);
347   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
348   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
349   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
350   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
353   while (next) {
354     DMLabel tmp = next->next;
355 
356     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
357     next = tmp;
358   }
359   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
360   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
361   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
362   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
363   ierr = PetscFree(mesh);CHKERRQ(ierr);
364   PetscFunctionReturn(0);
365 }
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
369 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
370 {
371   const PetscInt *support = PETSC_NULL;
372   PetscInt        numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
373   PetscErrorCode  ierr;
374 
375   PetscFunctionBegin;
376   if (useClosure) {
377     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
378     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
379     for (s = 0; s < supportSize; ++s) {
380       const PetscInt *cone = PETSC_NULL;
381       PetscInt        coneSize, c, q;
382 
383       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
384       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
385       for (c = 0; c < coneSize; ++c) {
386         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
387           if (cone[c] == adj[q]) break;
388         }
389         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
390       }
391     }
392   } else {
393     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
394     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
395     for (s = 0; s < supportSize; ++s) {
396       const PetscInt *cone = PETSC_NULL;
397       PetscInt        coneSize, c, q;
398 
399       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
400       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
401       for (c = 0; c < coneSize; ++c) {
402         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
403           if (cone[c] == adj[q]) break;
404         }
405         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
406       }
407     }
408   }
409   *adjSize = numAdj;
410   PetscFunctionReturn(0);
411 }
412 
413 #undef __FUNCT__
414 #define __FUNCT__ "DMPlexGetAdjacency_Private"
415 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
416 {
417   const PetscInt *star  = tmpClosure;
418   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
419   PetscErrorCode  ierr;
420 
421   PetscFunctionBegin;
422   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
423   for (s = 2; s < starSize*2; s += 2) {
424     const PetscInt *closure = PETSC_NULL;
425     PetscInt        closureSize, c, q;
426 
427     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
428     for (c = 0; c < closureSize*2; c += 2) {
429       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
430         if (closure[c] == adj[q]) break;
431       }
432       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
433     }
434     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
435   }
436   *adjSize = numAdj;
437   PetscFunctionReturn(0);
438 }
439 
440 #undef __FUNCT__
441 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
442 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
443 {
444   DM_Plex *mesh = (DM_Plex*) dm->data;
445 
446   PetscFunctionBegin;
447   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
448   mesh->preallocCenterDim = preallocCenterDim;
449   PetscFunctionReturn(0);
450 }
451 
452 #undef __FUNCT__
453 #define __FUNCT__ "DMPlexPreallocateOperator"
454 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
455 {
456   DM_Plex           *mesh = (DM_Plex*) dm->data;
457   MPI_Comm           comm  = ((PetscObject) dm)->comm;
458   PetscSF            sf, sfDof, sfAdj;
459   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
460   PetscInt           nleaves, l, p;
461   const PetscInt    *leaves;
462   const PetscSFNode *remotes;
463   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
464   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
465   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
466   PetscLayout        rLayout;
467   PetscInt           locRows, rStart, rEnd, r;
468   PetscMPIInt        size;
469   PetscBool          useClosure, debug = PETSC_FALSE;
470   PetscErrorCode     ierr;
471 
472   PetscFunctionBegin;
473   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
474   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
475   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
476   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
477   /* Create dof SF based on point SF */
478   if (debug) {
479     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
480     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
481     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
485   }
486   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
487   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
488   if (debug) {
489     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
490     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
491   }
492   /* Create section for dof adjacency (dof ==> # adj dof) */
493   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
494   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
495   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
496   if (mesh->preallocCenterDim == dim) {
497     useClosure = PETSC_FALSE;
498   } else if (mesh->preallocCenterDim == 0) {
499     useClosure = PETSC_TRUE;
500   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
501 
502   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
503   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
504   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
505   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
508   /*   Fill in the ghost dofs on the interface */
509   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
510   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
511   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
512 
513   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
514   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
515 
516   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
517 
518   /*
519    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
520     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
521        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
522     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
523        Create sfAdj connecting rootSectionAdj and leafSectionAdj
524     3. Visit unowned points on interface, write adjacencies to adj
525        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
526     4. Visit owned points on interface, write adjacencies to rootAdj
527        Remove redundancy in rootAdj
528    ** The last two traversals use transitive closure
529     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
530        Allocate memory addressed by sectionAdj (cols)
531     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
532    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
533   */
534 
535   for (l = 0; l < nleaves; ++l) {
536     PetscInt dof, off, d, q;
537     PetscInt p = leaves[l], numAdj = maxAdjSize;
538 
539     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
540     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
541     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
542     for (q = 0; q < numAdj; ++q) {
543       PetscInt ndof, ncdof;
544 
545       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
546       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
547       for (d = off; d < off+dof; ++d) {
548         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
549       }
550     }
551   }
552   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
553   if (debug) {
554     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
555     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
556   }
557   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
558   if (size > 1) {
559     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
560     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561   }
562   if (debug) {
563     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
564     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
565   }
566   /* Add in local adjacency sizes for owned dofs on interface (roots) */
567   for (p = pStart; p < pEnd; ++p) {
568     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
569 
570     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
571     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
572     if (!dof) continue;
573     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
574     if (adof <= 0) continue;
575     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
576     for (q = 0; q < numAdj; ++q) {
577       PetscInt ndof, ncdof;
578 
579       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
580       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
581       for (d = off; d < off+dof; ++d) {
582         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
583       }
584     }
585   }
586   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
587   if (debug) {
588     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
589     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
590   }
591   /* Create adj SF based on dof SF */
592   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
593   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
596     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
597   }
598   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
599   /* Create leaf adjacency */
600   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
601   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
602   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
603   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
604   for (l = 0; l < nleaves; ++l) {
605     PetscInt dof, off, d, q;
606     PetscInt p = leaves[l], numAdj = maxAdjSize;
607 
608     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
609     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
610     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
611     for (d = off; d < off+dof; ++d) {
612       PetscInt aoff, i = 0;
613 
614       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
615       for (q = 0; q < numAdj; ++q) {
616         PetscInt ndof, ncdof, ngoff, nd;
617 
618         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
619         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
620         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
621         for (nd = 0; nd < ndof-ncdof; ++nd) {
622           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
623           ++i;
624         }
625       }
626     }
627   }
628   /* Debugging */
629   if (debug) {
630     IS tmp;
631     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
632     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
633     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
634   }
635   /* Gather adjacenct indices to root */
636   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
637   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
638   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
639   if (size > 1) {
640     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
641     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
642   }
643   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
644   ierr = PetscFree(adj);CHKERRQ(ierr);
645   /* Debugging */
646   if (debug) {
647     IS tmp;
648     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
649     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
650     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
651   }
652   /* Add in local adjacency indices for owned dofs on interface (roots) */
653   for (p = pStart; p < pEnd; ++p) {
654     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
655 
656     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
657     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
658     if (!dof) continue;
659     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
660     if (adof <= 0) continue;
661     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
662     for (d = off; d < off+dof; ++d) {
663       PetscInt adof, aoff, i;
664 
665       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
666       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
667       i    = adof-1;
668       for (q = 0; q < numAdj; ++q) {
669         PetscInt ndof, ncdof, ngoff, nd;
670 
671         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
672         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
673         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
674         for (nd = 0; nd < ndof-ncdof; ++nd) {
675           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
676           --i;
677         }
678       }
679     }
680   }
681   /* Debugging */
682   if (debug) {
683     IS tmp;
684     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
685     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
686     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
687   }
688   /* Compress indices */
689   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
690   for (p = pStart; p < pEnd; ++p) {
691     PetscInt dof, cdof, off, d;
692     PetscInt adof, aoff;
693 
694     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
695     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
696     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
697     if (!dof) continue;
698     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
699     if (adof <= 0) continue;
700     for (d = off; d < off+dof-cdof; ++d) {
701       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
702       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
703       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
704       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
705     }
706   }
707   /* Debugging */
708   if (debug) {
709     IS tmp;
710     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
711     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
712     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
713     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
714     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
715   }
716   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
717   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
718   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
719   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
720   for (p = pStart; p < pEnd; ++p) {
721     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
722     PetscBool found  = PETSC_TRUE;
723 
724     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
725     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
726     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
727     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
728     for (d = 0; d < dof-cdof; ++d) {
729       PetscInt ldof, rdof;
730 
731       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
732       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
733       if (ldof > 0) {
734         /* We do not own this point */
735       } else if (rdof > 0) {
736         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
737       } else {
738         found = PETSC_FALSE;
739       }
740     }
741     if (found) continue;
742     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
743     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
744     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
745     for (q = 0; q < numAdj; ++q) {
746       PetscInt ndof, ncdof, noff;
747 
748       /* Adjacent points may not be in the section chart */
749       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
750       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
751       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
752       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
753       for (d = goff; d < goff+dof-cdof; ++d) {
754         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
755       }
756     }
757   }
758   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
759   if (debug) {
760     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
761     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
762   }
763   /* Get adjacent indices */
764   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
765   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
766   for (p = pStart; p < pEnd; ++p) {
767     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
768     PetscBool found  = PETSC_TRUE;
769 
770     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
771     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
772     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
773     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
774     for (d = 0; d < dof-cdof; ++d) {
775       PetscInt ldof, rdof;
776 
777       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
778       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
779       if (ldof > 0) {
780         /* We do not own this point */
781       } else if (rdof > 0) {
782         PetscInt aoff, roff;
783 
784         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
785         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
786         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
787       } else {
788         found = PETSC_FALSE;
789       }
790     }
791     if (found) continue;
792     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
793     for (d = goff; d < goff+dof-cdof; ++d) {
794       PetscInt adof, aoff, i = 0;
795 
796       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
797       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
798       for (q = 0; q < numAdj; ++q) {
799         PetscInt        ndof, ncdof, ngoff, nd;
800         const PetscInt *ncind;
801 
802         /* Adjacent points may not be in the section chart */
803         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
804         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
805         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
806         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
807         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
808         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
809           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
810         }
811       }
812       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);
813     }
814   }
815   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
816   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
817   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
818   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
819   /* Debugging */
820   if (debug) {
821     IS tmp;
822     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
823     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
824     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
825   }
826   /* Create allocation vectors from adjacency graph */
827   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
828   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
829   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
830   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
831   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
832   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
833   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
834   /* Only loop over blocks of rows */
835   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
836   for (r = rStart/bs; r < rEnd/bs; ++r) {
837     const PetscInt row = r*bs;
838     PetscInt       numCols, cStart, c;
839 
840     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
841     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
842     for (c = cStart; c < cStart+numCols; ++c) {
843       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
844         ++dnz[r-rStart];
845         if (cols[c] >= row) ++dnzu[r-rStart];
846       } else {
847         ++onz[r-rStart];
848         if (cols[c] >= row) ++onzu[r-rStart];
849       }
850     }
851   }
852   if (bs > 1) {
853     for (r = 0; r < locRows/bs; ++r) {
854       dnz[r]  /= bs;
855       onz[r]  /= bs;
856       dnzu[r] /= bs;
857       onzu[r] /= bs;
858     }
859   }
860   /* Set matrix pattern */
861   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
862   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
863   /* Fill matrix with zeros */
864   if (fillMatrix) {
865     PetscScalar *values;
866     PetscInt     maxRowLen = 0;
867 
868     for (r = rStart; r < rEnd; ++r) {
869       PetscInt len;
870 
871       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
872       maxRowLen = PetscMax(maxRowLen, len);
873     }
874     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
875     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
876     for (r = rStart; r < rEnd; ++r) {
877       PetscInt numCols, cStart;
878 
879       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
880       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
881       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
882     }
883     ierr = PetscFree(values);CHKERRQ(ierr);
884     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
885     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
886   }
887   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
888   ierr = PetscFree(cols);CHKERRQ(ierr);
889   PetscFunctionReturn(0);
890 }
891 
892 #if 0
893 #undef __FUNCT__
894 #define __FUNCT__ "DMPlexPreallocateOperator_2"
895 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
896 {
897   PetscInt       *tmpClosure,*tmpAdj,*visits;
898   PetscInt        c,cStart,cEnd,pStart,pEnd;
899   PetscErrorCode  ierr;
900 
901   PetscFunctionBegin;
902   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
903   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
904   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
905 
906   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
907 
908   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910 
911   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
912   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
914   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
915   for (c=cStart; c<cEnd; c++) {
916     PetscInt *support = tmpClosure;
917     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
918     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
919   }
920   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
921   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
923   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924 
925   ierr = PetscSFGetRanks();CHKERRQ(ierr);
926 
927 
928   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
929   for (c=cStart; c<cEnd; c++) {
930     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
931     /*
932      Depth-first walk of transitive closure.
933      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.
934      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
935      */
936   }
937 
938   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
939   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
940   PetscFunctionReturn(0);
941 }
942 #endif
943 
944 #undef __FUNCT__
945 #define __FUNCT__ "DMCreateMatrix_Plex"
946 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
947 {
948   PetscSection   section, sectionGlobal;
949   PetscInt       bs = -1;
950   PetscInt       localSize;
951   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
952   PetscErrorCode ierr;
953 
954   PetscFunctionBegin;
955 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
956   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
957 #endif
958   if (!mtype) mtype = MATAIJ;
959   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
960   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
961   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
962   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
963   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
964   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
965   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
966   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
967   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
974   /* Check for symmetric storage */
975   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
976   if (isSymmetric) {
977     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
978   }
979   if (!isShell) {
980     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
981     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
982 
983     if (bs < 0) {
984       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
985         PetscInt pStart, pEnd, p, dof, cdof;
986 
987         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
988         for (p = pStart; p < pEnd; ++p) {
989           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
990           ierr = PetscSectionGetConstraintDof(sectionGlobal, p, &cdof);CHKERRQ(ierr);
991           if (dof-cdof) {
992             if (bs < 0) {
993               bs = dof-cdof;
994             } else if (bs != dof-cdof) {
995               /* Layout does not admit a pointwise block size */
996               bs = 1;
997               break;
998             }
999           }
1000         }
1001         /* Must have same blocksize on all procs (some might have no points) */
1002         bsLocal = bs;
1003         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1004         bsLocal = bs < 0 ? bsMax : bs;
1005         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1006         if (bsMin != bsMax) {
1007           bs = 1;
1008         } else {
1009           bs = bsMax;
1010         }
1011       } else {
1012         bs = 1;
1013       }
1014     }
1015     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1016     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1017     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1018     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1019     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1020     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1021     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1022   }
1023   PetscFunctionReturn(0);
1024 }
1025 
1026 #undef __FUNCT__
1027 #define __FUNCT__ "DMPlexGetDimension"
1028 /*@
1029   DMPlexGetDimension - Return the topological mesh dimension
1030 
1031   Not collective
1032 
1033   Input Parameter:
1034 . mesh - The DMPlex
1035 
1036   Output Parameter:
1037 . dim - The topological mesh dimension
1038 
1039   Level: beginner
1040 
1041 .seealso: DMPlexCreate()
1042 @*/
1043 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1044 {
1045   DM_Plex *mesh = (DM_Plex*) dm->data;
1046 
1047   PetscFunctionBegin;
1048   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1049   PetscValidPointer(dim, 2);
1050   *dim = mesh->dim;
1051   PetscFunctionReturn(0);
1052 }
1053 
1054 #undef __FUNCT__
1055 #define __FUNCT__ "DMPlexSetDimension"
1056 /*@
1057   DMPlexSetDimension - Set the topological mesh dimension
1058 
1059   Collective on mesh
1060 
1061   Input Parameters:
1062 + mesh - The DMPlex
1063 - dim - The topological mesh dimension
1064 
1065   Level: beginner
1066 
1067 .seealso: DMPlexCreate()
1068 @*/
1069 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1070 {
1071   DM_Plex *mesh = (DM_Plex*) dm->data;
1072 
1073   PetscFunctionBegin;
1074   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1075   PetscValidLogicalCollectiveInt(dm, dim, 2);
1076   mesh->dim               = dim;
1077   mesh->preallocCenterDim = dim;
1078   PetscFunctionReturn(0);
1079 }
1080 
1081 #undef __FUNCT__
1082 #define __FUNCT__ "DMPlexGetChart"
1083 /*@
1084   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1085 
1086   Not collective
1087 
1088   Input Parameter:
1089 . mesh - The DMPlex
1090 
1091   Output Parameters:
1092 + pStart - The first mesh point
1093 - pEnd   - The upper bound for mesh points
1094 
1095   Level: beginner
1096 
1097 .seealso: DMPlexCreate(), DMPlexSetChart()
1098 @*/
1099 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1100 {
1101   DM_Plex       *mesh = (DM_Plex*) dm->data;
1102   PetscErrorCode ierr;
1103 
1104   PetscFunctionBegin;
1105   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1106   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1107   PetscFunctionReturn(0);
1108 }
1109 
1110 #undef __FUNCT__
1111 #define __FUNCT__ "DMPlexSetChart"
1112 /*@
1113   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1114 
1115   Not collective
1116 
1117   Input Parameters:
1118 + mesh - The DMPlex
1119 . pStart - The first mesh point
1120 - pEnd   - The upper bound for mesh points
1121 
1122   Output Parameters:
1123 
1124   Level: beginner
1125 
1126 .seealso: DMPlexCreate(), DMPlexGetChart()
1127 @*/
1128 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1129 {
1130   DM_Plex       *mesh = (DM_Plex*) dm->data;
1131   PetscErrorCode ierr;
1132 
1133   PetscFunctionBegin;
1134   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1135   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1136   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1137   PetscFunctionReturn(0);
1138 }
1139 
1140 #undef __FUNCT__
1141 #define __FUNCT__ "DMPlexGetConeSize"
1142 /*@
1143   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1144 
1145   Not collective
1146 
1147   Input Parameters:
1148 + mesh - The DMPlex
1149 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1150 
1151   Output Parameter:
1152 . size - The cone size for point p
1153 
1154   Level: beginner
1155 
1156 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1157 @*/
1158 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1159 {
1160   DM_Plex       *mesh = (DM_Plex*) dm->data;
1161   PetscErrorCode ierr;
1162 
1163   PetscFunctionBegin;
1164   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1165   PetscValidPointer(size, 3);
1166   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1167   PetscFunctionReturn(0);
1168 }
1169 
1170 #undef __FUNCT__
1171 #define __FUNCT__ "DMPlexSetConeSize"
1172 /*@
1173   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1174 
1175   Not collective
1176 
1177   Input Parameters:
1178 + mesh - The DMPlex
1179 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1180 - size - The cone size for point p
1181 
1182   Output Parameter:
1183 
1184   Note:
1185   This should be called after DMPlexSetChart().
1186 
1187   Level: beginner
1188 
1189 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1190 @*/
1191 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1192 {
1193   DM_Plex       *mesh = (DM_Plex*) dm->data;
1194   PetscErrorCode ierr;
1195 
1196   PetscFunctionBegin;
1197   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1198   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1199 
1200   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1201   PetscFunctionReturn(0);
1202 }
1203 
1204 #undef __FUNCT__
1205 #define __FUNCT__ "DMPlexGetCone"
1206 /*@C
1207   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1208 
1209   Not collective
1210 
1211   Input Parameters:
1212 + mesh - The DMPlex
1213 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1214 
1215   Output Parameter:
1216 . cone - An array of points which are on the in-edges for point p
1217 
1218   Level: beginner
1219 
1220   Note:
1221   This routine is not available in Fortran.
1222 
1223 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1224 @*/
1225 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1226 {
1227   DM_Plex       *mesh = (DM_Plex*) dm->data;
1228   PetscInt       off;
1229   PetscErrorCode ierr;
1230 
1231   PetscFunctionBegin;
1232   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1233   PetscValidPointer(cone, 3);
1234   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1235   *cone = &mesh->cones[off];
1236   PetscFunctionReturn(0);
1237 }
1238 
1239 #undef __FUNCT__
1240 #define __FUNCT__ "DMPlexSetCone"
1241 /*@
1242   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1243 
1244   Not collective
1245 
1246   Input Parameters:
1247 + mesh - The DMPlex
1248 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1249 - cone - An array of points which are on the in-edges for point p
1250 
1251   Output Parameter:
1252 
1253   Note:
1254   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1255 
1256   Level: beginner
1257 
1258 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1259 @*/
1260 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1261 {
1262   DM_Plex       *mesh = (DM_Plex*) dm->data;
1263   PetscInt       pStart, pEnd;
1264   PetscInt       dof, off, c;
1265   PetscErrorCode ierr;
1266 
1267   PetscFunctionBegin;
1268   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1269   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1270   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1271   if (dof) PetscValidPointer(cone, 3);
1272   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1273   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1274   for (c = 0; c < dof; ++c) {
1275     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1276     mesh->cones[off+c] = cone[c];
1277   }
1278   PetscFunctionReturn(0);
1279 }
1280 
1281 #undef __FUNCT__
1282 #define __FUNCT__ "DMPlexGetConeOrientation"
1283 /*@C
1284   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1285 
1286   Not collective
1287 
1288   Input Parameters:
1289 + mesh - The DMPlex
1290 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1291 
1292   Output Parameter:
1293 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1294                     integer giving the prescription for cone traversal. If it is negative, the cone is
1295                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1296                     the index of the cone point on which to start.
1297 
1298   Level: beginner
1299 
1300   Note:
1301   This routine is not available in Fortran.
1302 
1303 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1304 @*/
1305 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1306 {
1307   DM_Plex       *mesh = (DM_Plex*) dm->data;
1308   PetscInt       off;
1309   PetscErrorCode ierr;
1310 
1311   PetscFunctionBegin;
1312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1313 #if defined(PETSC_USE_DEBUG)
1314   {
1315     PetscInt dof;
1316     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1317     if (dof) PetscValidPointer(coneOrientation, 3);
1318   }
1319 #endif
1320   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1321 
1322   *coneOrientation = &mesh->coneOrientations[off];
1323   PetscFunctionReturn(0);
1324 }
1325 
1326 #undef __FUNCT__
1327 #define __FUNCT__ "DMPlexSetConeOrientation"
1328 /*@
1329   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1330 
1331   Not collective
1332 
1333   Input Parameters:
1334 + mesh - The DMPlex
1335 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1336 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1337                     integer giving the prescription for cone traversal. If it is negative, the cone is
1338                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1339                     the index of the cone point on which to start.
1340 
1341   Output Parameter:
1342 
1343   Note:
1344   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1345 
1346   Level: beginner
1347 
1348 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1349 @*/
1350 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1351 {
1352   DM_Plex       *mesh = (DM_Plex*) dm->data;
1353   PetscInt       pStart, pEnd;
1354   PetscInt       dof, off, c;
1355   PetscErrorCode ierr;
1356 
1357   PetscFunctionBegin;
1358   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1359   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1360   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1361   if (dof) PetscValidPointer(coneOrientation, 3);
1362   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1363   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1364   for (c = 0; c < dof; ++c) {
1365     PetscInt cdof, o = coneOrientation[c];
1366 
1367     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1368     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1369     mesh->coneOrientations[off+c] = o;
1370   }
1371   PetscFunctionReturn(0);
1372 }
1373 
1374 #undef __FUNCT__
1375 #define __FUNCT__ "DMPlexInsertCone"
1376 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1377 {
1378   DM_Plex       *mesh = (DM_Plex*) dm->data;
1379   PetscInt       pStart, pEnd;
1380   PetscInt       dof, off;
1381   PetscErrorCode ierr;
1382 
1383   PetscFunctionBegin;
1384   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1385   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1386   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1387   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1388   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1389   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1390   if (conePos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1391   mesh->cones[off+conePos] = conePoint;
1392   PetscFunctionReturn(0);
1393 }
1394 
1395 #undef __FUNCT__
1396 #define __FUNCT__ "DMPlexGetSupportSize"
1397 /*@
1398   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1399 
1400   Not collective
1401 
1402   Input Parameters:
1403 + mesh - The DMPlex
1404 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1405 
1406   Output Parameter:
1407 . size - The support size for point p
1408 
1409   Level: beginner
1410 
1411 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1412 @*/
1413 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1414 {
1415   DM_Plex       *mesh = (DM_Plex*) dm->data;
1416   PetscErrorCode ierr;
1417 
1418   PetscFunctionBegin;
1419   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1420   PetscValidPointer(size, 3);
1421   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1422   PetscFunctionReturn(0);
1423 }
1424 
1425 #undef __FUNCT__
1426 #define __FUNCT__ "DMPlexSetSupportSize"
1427 /*@
1428   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1429 
1430   Not collective
1431 
1432   Input Parameters:
1433 + mesh - The DMPlex
1434 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1435 - size - The support size for point p
1436 
1437   Output Parameter:
1438 
1439   Note:
1440   This should be called after DMPlexSetChart().
1441 
1442   Level: beginner
1443 
1444 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1445 @*/
1446 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1447 {
1448   DM_Plex       *mesh = (DM_Plex*) dm->data;
1449   PetscErrorCode ierr;
1450 
1451   PetscFunctionBegin;
1452   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1453   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1454 
1455   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1456   PetscFunctionReturn(0);
1457 }
1458 
1459 #undef __FUNCT__
1460 #define __FUNCT__ "DMPlexGetSupport"
1461 /*@C
1462   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1463 
1464   Not collective
1465 
1466   Input Parameters:
1467 + mesh - The DMPlex
1468 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1469 
1470   Output Parameter:
1471 . support - An array of points which are on the out-edges for point p
1472 
1473   Level: beginner
1474 
1475 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1476 @*/
1477 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1478 {
1479   DM_Plex       *mesh = (DM_Plex*) dm->data;
1480   PetscInt       off;
1481   PetscErrorCode ierr;
1482 
1483   PetscFunctionBegin;
1484   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1485   PetscValidPointer(support, 3);
1486   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1487   *support = &mesh->supports[off];
1488   PetscFunctionReturn(0);
1489 }
1490 
1491 #undef __FUNCT__
1492 #define __FUNCT__ "DMPlexSetSupport"
1493 /*@
1494   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1495 
1496   Not collective
1497 
1498   Input Parameters:
1499 + mesh - The DMPlex
1500 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1501 - support - An array of points which are on the in-edges for point p
1502 
1503   Output Parameter:
1504 
1505   Note:
1506   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1507 
1508   Level: beginner
1509 
1510 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1511 @*/
1512 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1513 {
1514   DM_Plex       *mesh = (DM_Plex*) dm->data;
1515   PetscInt       pStart, pEnd;
1516   PetscInt       dof, off, c;
1517   PetscErrorCode ierr;
1518 
1519   PetscFunctionBegin;
1520   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1521   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1522   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1523   if (dof) PetscValidPointer(support, 3);
1524   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1525   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1526   for (c = 0; c < dof; ++c) {
1527     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1528     mesh->supports[off+c] = support[c];
1529   }
1530   PetscFunctionReturn(0);
1531 }
1532 
1533 #undef __FUNCT__
1534 #define __FUNCT__ "DMPlexInsertSupport"
1535 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1536 {
1537   DM_Plex       *mesh = (DM_Plex*) dm->data;
1538   PetscInt       pStart, pEnd;
1539   PetscInt       dof, off;
1540   PetscErrorCode ierr;
1541 
1542   PetscFunctionBegin;
1543   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1544   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1545   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1546   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1547   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1548   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1549   if (supportPos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1550   mesh->supports[off+supportPos] = supportPoint;
1551   PetscFunctionReturn(0);
1552 }
1553 
1554 #undef __FUNCT__
1555 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1556 /*@C
1557   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1558 
1559   Not collective
1560 
1561   Input Parameters:
1562 + mesh - The DMPlex
1563 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1564 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1565 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1566 
1567   Output Parameters:
1568 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1569 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1570 
1571   Note:
1572   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1573 
1574   Level: beginner
1575 
1576 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1577 @*/
1578 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1579 {
1580   DM_Plex        *mesh = (DM_Plex*) dm->data;
1581   PetscInt       *closure, *fifo;
1582   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1583   PetscInt        tmpSize, t;
1584   PetscInt        depth       = 0, maxSize;
1585   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1586   PetscErrorCode  ierr;
1587 
1588   PetscFunctionBegin;
1589   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1590   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1591   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1592   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1593   if (*points) {
1594     closure = *points;
1595   } else {
1596     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1597   }
1598   closure[0] = p; closure[1] = 0;
1599   /* This is only 1-level */
1600   if (useCone) {
1601     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1602     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1603     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1604   } else {
1605     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1606     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1607   }
1608   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1609     const PetscInt cp = tmp[t];
1610     const PetscInt co = tmpO ? tmpO[t] : 0;
1611 
1612     closure[closureSize]   = cp;
1613     closure[closureSize+1] = co;
1614     fifo[fifoSize]         = cp;
1615     fifo[fifoSize+1]       = co;
1616   }
1617   while (fifoSize - fifoStart) {
1618     const PetscInt q   = fifo[fifoStart];
1619     const PetscInt o   = fifo[fifoStart+1];
1620     const PetscInt rev = o >= 0 ? 0 : 1;
1621     const PetscInt off = rev ? -(o+1) : o;
1622 
1623     if (useCone) {
1624       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1625       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1626       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1627     } else {
1628       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1629       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1630       tmpO = PETSC_NULL;
1631     }
1632     for (t = 0; t < tmpSize; ++t) {
1633       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1634       const PetscInt cp = tmp[i];
1635       /* Must propogate orientation */
1636       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1637       PetscInt       c;
1638 
1639       /* Check for duplicate */
1640       for (c = 0; c < closureSize; c += 2) {
1641         if (closure[c] == cp) break;
1642       }
1643       if (c == closureSize) {
1644         closure[closureSize]   = cp;
1645         closure[closureSize+1] = co;
1646         fifo[fifoSize]         = cp;
1647         fifo[fifoSize+1]       = co;
1648         closureSize           += 2;
1649         fifoSize              += 2;
1650       }
1651     }
1652     fifoStart += 2;
1653   }
1654   if (numPoints) *numPoints = closureSize/2;
1655   if (points)    *points    = closure;
1656   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1657   PetscFunctionReturn(0);
1658 }
1659 
1660 #undef __FUNCT__
1661 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1662 /*@C
1663   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1664 
1665   Not collective
1666 
1667   Input Parameters:
1668 + mesh - The DMPlex
1669 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1670 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1671 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1672 
1673   Output Parameters:
1674 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1675 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1676 
1677   Note:
1678   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1679 
1680   Level: beginner
1681 
1682 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1683 @*/
1684 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1685 {
1686   PetscErrorCode ierr;
1687 
1688   PetscFunctionBegin;
1689   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1690   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1691   PetscFunctionReturn(0);
1692 }
1693 
1694 #undef __FUNCT__
1695 #define __FUNCT__ "DMPlexGetFaces"
1696 /*
1697   DMPlexGetFaces -
1698 
1699   Note: This will only work for cell-vertex meshes.
1700 */
1701 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1702 {
1703   DM_Plex        *mesh = (DM_Plex*) dm->data;
1704   const PetscInt *cone = PETSC_NULL;
1705   PetscInt        depth = 0, dim, coneSize;
1706   PetscErrorCode  ierr;
1707 
1708   PetscFunctionBegin;
1709   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1710   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1711   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1712   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1713   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1714   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1715   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1716   switch (dim) {
1717   case 2:
1718     switch (coneSize) {
1719     case 3:
1720       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1721       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1722       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1723       *numFaces         = 3;
1724       *faceSize         = 2;
1725       *faces            = mesh->facesTmp;
1726       break;
1727     case 4:
1728       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1729       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1730       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1731       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1732       *numFaces         = 4;
1733       *faceSize         = 2;
1734       *faces            = mesh->facesTmp;
1735       break;
1736     default:
1737       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1738     }
1739     break;
1740   case 3:
1741     switch (coneSize) {
1742     case 3:
1743       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1744       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1745       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1746       *numFaces         = 3;
1747       *faceSize         = 2;
1748       *faces            = mesh->facesTmp;
1749       break;
1750     case 4:
1751       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1752       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1753       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1754       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1755       *numFaces         = 4;
1756       *faceSize         = 3;
1757       *faces            = mesh->facesTmp;
1758       break;
1759     default:
1760       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1761     }
1762     break;
1763   default:
1764     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1765   }
1766   PetscFunctionReturn(0);
1767 }
1768 
1769 #undef __FUNCT__
1770 #define __FUNCT__ "DMPlexGetMaxSizes"
1771 /*@
1772   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1773 
1774   Not collective
1775 
1776   Input Parameter:
1777 . mesh - The DMPlex
1778 
1779   Output Parameters:
1780 + maxConeSize - The maximum number of in-edges
1781 - maxSupportSize - The maximum number of out-edges
1782 
1783   Level: beginner
1784 
1785 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1786 @*/
1787 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1788 {
1789   DM_Plex *mesh = (DM_Plex*) dm->data;
1790 
1791   PetscFunctionBegin;
1792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1793   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1794   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1795   PetscFunctionReturn(0);
1796 }
1797 
1798 #undef __FUNCT__
1799 #define __FUNCT__ "DMSetUp_Plex"
1800 PetscErrorCode DMSetUp_Plex(DM dm)
1801 {
1802   DM_Plex       *mesh = (DM_Plex*) dm->data;
1803   PetscInt       size;
1804   PetscErrorCode ierr;
1805 
1806   PetscFunctionBegin;
1807   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1808   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1809   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1810   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1811   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1812   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1813   if (mesh->maxSupportSize) {
1814     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1815     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1816     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1817   }
1818   PetscFunctionReturn(0);
1819 }
1820 
1821 #undef __FUNCT__
1822 #define __FUNCT__ "DMCreateSubDM_Plex"
1823 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1824 {
1825   PetscSection   section, sectionGlobal;
1826   PetscInt      *subIndices;
1827   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1828   PetscErrorCode ierr;
1829 
1830   PetscFunctionBegin;
1831   if (!numFields) PetscFunctionReturn(0);
1832   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1833   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1834   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1835   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1836   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1837   if (numFields > nF) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1838   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1839   for (p = pStart; p < pEnd; ++p) {
1840     PetscInt gdof;
1841 
1842     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1843     if (gdof > 0) {
1844       for (f = 0; f < numFields; ++f) {
1845         PetscInt fdof, fcdof;
1846 
1847         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1848         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1849         subSize += fdof-fcdof;
1850       }
1851     }
1852   }
1853   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1854   for (p = pStart; p < pEnd; ++p) {
1855     PetscInt gdof, goff;
1856 
1857     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1858     if (gdof > 0) {
1859       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1860       for (f = 0; f < numFields; ++f) {
1861         PetscInt fdof, fcdof, fc, f2, poff = 0;
1862 
1863         /* Can get rid of this loop by storing field information in the global section */
1864         for (f2 = 0; f2 < fields[f]; ++f2) {
1865           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1866           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1867           poff += fdof-fcdof;
1868         }
1869         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1870         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1871         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1872           subIndices[subOff] = goff+poff+fc;
1873         }
1874       }
1875     }
1876   }
1877   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1878   if (subdm) {
1879     PetscSection subsection;
1880     PetscBool    haveNull = PETSC_FALSE;
1881     PetscInt     f, nf = 0;
1882 
1883     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1884     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1885     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1886     for (f = 0; f < numFields; ++f) {
1887       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1888       if ((*subdm)->nullspaceConstructors[f]) {
1889         haveNull = PETSC_TRUE;
1890         nf       = f;
1891       }
1892     }
1893     if (haveNull) {
1894       MatNullSpace nullSpace;
1895 
1896       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1897       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1898       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1899     }
1900     if (dm->fields) {
1901       if (nF != dm->numFields) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1902       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1903       for (f = 0; f < numFields; ++f) {
1904         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1905       }
1906       if (numFields == 1) {
1907         MatNullSpace space;
1908         Mat          pmat;
1909 
1910         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1911         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1912         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1913         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1914         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1915         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1916       }
1917     }
1918   }
1919   PetscFunctionReturn(0);
1920 }
1921 
1922 #undef __FUNCT__
1923 #define __FUNCT__ "DMPlexSymmetrize"
1924 /*@
1925   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1926 
1927   Not collective
1928 
1929   Input Parameter:
1930 . mesh - The DMPlex
1931 
1932   Output Parameter:
1933 
1934   Note:
1935   This should be called after all calls to DMPlexSetCone()
1936 
1937   Level: beginner
1938 
1939 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1940 @*/
1941 PetscErrorCode DMPlexSymmetrize(DM dm)
1942 {
1943   DM_Plex       *mesh = (DM_Plex*) dm->data;
1944   PetscInt      *offsets;
1945   PetscInt       supportSize;
1946   PetscInt       pStart, pEnd, p;
1947   PetscErrorCode ierr;
1948 
1949   PetscFunctionBegin;
1950   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1951   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1952   /* Calculate support sizes */
1953   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1954   for (p = pStart; p < pEnd; ++p) {
1955     PetscInt dof, off, c;
1956 
1957     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1958     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1959     for (c = off; c < off+dof; ++c) {
1960       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1961     }
1962   }
1963   for (p = pStart; p < pEnd; ++p) {
1964     PetscInt dof;
1965 
1966     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1967 
1968     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1969   }
1970   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1971   /* Calculate supports */
1972   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1973   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1974   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1975   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1976   for (p = pStart; p < pEnd; ++p) {
1977     PetscInt dof, off, c;
1978 
1979     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1980     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1981     for (c = off; c < off+dof; ++c) {
1982       const PetscInt q = mesh->cones[c];
1983       PetscInt       offS;
1984 
1985       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1986 
1987       mesh->supports[offS+offsets[q]] = p;
1988       ++offsets[q];
1989     }
1990   }
1991   ierr = PetscFree(offsets);CHKERRQ(ierr);
1992   PetscFunctionReturn(0);
1993 }
1994 
1995 #undef __FUNCT__
1996 #define __FUNCT__ "DMPlexSetDepth_Private"
1997 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1998 {
1999   PetscInt       d;
2000   PetscErrorCode ierr;
2001 
2002   PetscFunctionBegin;
2003   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2004   if (d < 0) {
2005     /* We are guaranteed that the point has a cone since the depth was not yet set */
2006     const PetscInt *cone = PETSC_NULL;
2007     PetscInt        dCone;
2008 
2009     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2010     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2011     d    = dCone+1;
2012     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2013   }
2014   *depth = d;
2015   PetscFunctionReturn(0);
2016 }
2017 
2018 #undef __FUNCT__
2019 #define __FUNCT__ "DMPlexStratify"
2020 /*@
2021   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2022   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2023   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2024   the DAG.
2025 
2026   Not collective
2027 
2028   Input Parameter:
2029 . mesh - The DMPlex
2030 
2031   Output Parameter:
2032 
2033   Notes:
2034   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2035   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2036 
2037   This should be called after all calls to DMPlexSymmetrize()
2038 
2039   Level: beginner
2040 
2041 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2042 @*/
2043 PetscErrorCode DMPlexStratify(DM dm)
2044 {
2045   DM_Plex       *mesh = (DM_Plex*) dm->data;
2046   PetscInt       pStart, pEnd, p;
2047   PetscInt       numRoots = 0, numLeaves = 0;
2048   PetscErrorCode ierr;
2049 
2050   PetscFunctionBegin;
2051   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2052   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2053   /* Calculate depth */
2054   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2055   /* Initialize roots and count leaves */
2056   for (p = pStart; p < pEnd; ++p) {
2057     PetscInt coneSize, supportSize;
2058 
2059     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2060     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2061     if (!coneSize && supportSize) {
2062       ++numRoots;
2063       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2064     } else if (!supportSize && coneSize) {
2065       ++numLeaves;
2066     } else if (!supportSize && !coneSize) {
2067       /* Isolated points */
2068       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2069     }
2070   }
2071   if (numRoots + numLeaves == (pEnd - pStart)) {
2072     for (p = pStart; p < pEnd; ++p) {
2073       PetscInt coneSize, supportSize;
2074 
2075       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2076       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2077       if (!supportSize && coneSize) {
2078         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2079       }
2080     }
2081   } else {
2082     /* This might be slow since lookup is not fast */
2083     for (p = pStart; p < pEnd; ++p) {
2084       PetscInt depth;
2085 
2086       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2087     }
2088   }
2089   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2090   PetscFunctionReturn(0);
2091 }
2092 
2093 #undef __FUNCT__
2094 #define __FUNCT__ "DMPlexGetJoin"
2095 /*@C
2096   DMPlexGetJoin - Get an array for the join of the set of points
2097 
2098   Not Collective
2099 
2100   Input Parameters:
2101 + dm - The DMPlex object
2102 . numPoints - The number of input points for the join
2103 - points - The input points
2104 
2105   Output Parameters:
2106 + numCoveredPoints - The number of points in the join
2107 - coveredPoints - The points in the join
2108 
2109   Level: intermediate
2110 
2111   Note: Currently, this is restricted to a single level join
2112 
2113 .keywords: mesh
2114 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2115 @*/
2116 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2117 {
2118   DM_Plex       *mesh = (DM_Plex*) dm->data;
2119   PetscInt      *join[2];
2120   PetscInt       joinSize, i = 0;
2121   PetscInt       dof, off, p, c, m;
2122   PetscErrorCode ierr;
2123 
2124   PetscFunctionBegin;
2125   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2126   PetscValidPointer(points, 2);
2127   PetscValidPointer(numCoveredPoints, 3);
2128   PetscValidPointer(coveredPoints, 4);
2129   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2130   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2131   /* Copy in support of first point */
2132   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2133   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2134   for (joinSize = 0; joinSize < dof; ++joinSize) {
2135     join[i][joinSize] = mesh->supports[off+joinSize];
2136   }
2137   /* Check each successive support */
2138   for (p = 1; p < numPoints; ++p) {
2139     PetscInt newJoinSize = 0;
2140 
2141     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2142     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2143     for (c = 0; c < dof; ++c) {
2144       const PetscInt point = mesh->supports[off+c];
2145 
2146       for (m = 0; m < joinSize; ++m) {
2147         if (point == join[i][m]) {
2148           join[1-i][newJoinSize++] = point;
2149           break;
2150         }
2151       }
2152     }
2153     joinSize = newJoinSize;
2154     i        = 1-i;
2155   }
2156   *numCoveredPoints = joinSize;
2157   *coveredPoints    = join[i];
2158   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2159   PetscFunctionReturn(0);
2160 }
2161 
2162 #undef __FUNCT__
2163 #define __FUNCT__ "DMPlexRestoreJoin"
2164 /*@C
2165   DMPlexRestoreJoin - Restore an array for the join of the set of points
2166 
2167   Not Collective
2168 
2169   Input Parameters:
2170 + dm - The DMPlex object
2171 . numPoints - The number of input points for the join
2172 - points - The input points
2173 
2174   Output Parameters:
2175 + numCoveredPoints - The number of points in the join
2176 - coveredPoints - The points in the join
2177 
2178   Level: intermediate
2179 
2180 .keywords: mesh
2181 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2182 @*/
2183 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2184 {
2185   PetscErrorCode ierr;
2186 
2187   PetscFunctionBegin;
2188   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2189   PetscValidPointer(coveredPoints, 4);
2190   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2191   PetscFunctionReturn(0);
2192 }
2193 
2194 #undef __FUNCT__
2195 #define __FUNCT__ "DMPlexGetFullJoin"
2196 /*@C
2197   DMPlexGetFullJoin - Get an array for the join of the set of points
2198 
2199   Not Collective
2200 
2201   Input Parameters:
2202 + dm - The DMPlex object
2203 . numPoints - The number of input points for the join
2204 - points - The input points
2205 
2206   Output Parameters:
2207 + numCoveredPoints - The number of points in the join
2208 - coveredPoints - The points in the join
2209 
2210   Level: intermediate
2211 
2212 .keywords: mesh
2213 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2214 @*/
2215 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2216 {
2217   DM_Plex       *mesh = (DM_Plex*) dm->data;
2218   PetscInt      *offsets, **closures;
2219   PetscInt      *join[2];
2220   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2221   PetscInt       p, d, c, m;
2222   PetscErrorCode ierr;
2223 
2224   PetscFunctionBegin;
2225   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2226   PetscValidPointer(points, 2);
2227   PetscValidPointer(numCoveredPoints, 3);
2228   PetscValidPointer(coveredPoints, 4);
2229 
2230   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2231   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2232   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2233   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2234   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2235   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2236   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2237 
2238   for (p = 0; p < numPoints; ++p) {
2239     PetscInt closureSize;
2240 
2241     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2242 
2243     offsets[p*(depth+2)+0] = 0;
2244     for (d = 0; d < depth+1; ++d) {
2245       PetscInt pStart, pEnd, i;
2246 
2247       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2248       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2249         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2250           offsets[p*(depth+2)+d+1] = i;
2251           break;
2252         }
2253       }
2254       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2255     }
2256     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2257   }
2258   for (d = 0; d < depth+1; ++d) {
2259     PetscInt dof;
2260 
2261     /* Copy in support of first point */
2262     dof = offsets[d+1] - offsets[d];
2263     for (joinSize = 0; joinSize < dof; ++joinSize) {
2264       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2265     }
2266     /* Check each successive cone */
2267     for (p = 1; p < numPoints && joinSize; ++p) {
2268       PetscInt newJoinSize = 0;
2269 
2270       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2271       for (c = 0; c < dof; ++c) {
2272         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2273 
2274         for (m = 0; m < joinSize; ++m) {
2275           if (point == join[i][m]) {
2276             join[1-i][newJoinSize++] = point;
2277             break;
2278           }
2279         }
2280       }
2281       joinSize = newJoinSize;
2282       i        = 1-i;
2283     }
2284     if (joinSize) break;
2285   }
2286   *numCoveredPoints = joinSize;
2287   *coveredPoints    = join[i];
2288   for (p = 0; p < numPoints; ++p) {
2289     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2290   }
2291   ierr = PetscFree(closures);CHKERRQ(ierr);
2292   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2293   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2294   PetscFunctionReturn(0);
2295 }
2296 
2297 #undef __FUNCT__
2298 #define __FUNCT__ "DMPlexGetMeet"
2299 /*@C
2300   DMPlexGetMeet - Get an array for the meet of the set of points
2301 
2302   Not Collective
2303 
2304   Input Parameters:
2305 + dm - The DMPlex object
2306 . numPoints - The number of input points for the meet
2307 - points - The input points
2308 
2309   Output Parameters:
2310 + numCoveredPoints - The number of points in the meet
2311 - coveredPoints - The points in the meet
2312 
2313   Level: intermediate
2314 
2315   Note: Currently, this is restricted to a single level meet
2316 
2317 .keywords: mesh
2318 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2319 @*/
2320 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2321 {
2322   DM_Plex       *mesh = (DM_Plex*) dm->data;
2323   PetscInt      *meet[2];
2324   PetscInt       meetSize, i = 0;
2325   PetscInt       dof, off, p, c, m;
2326   PetscErrorCode ierr;
2327 
2328   PetscFunctionBegin;
2329   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2330   PetscValidPointer(points, 2);
2331   PetscValidPointer(numCoveringPoints, 3);
2332   PetscValidPointer(coveringPoints, 4);
2333   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2334   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2335   /* Copy in cone of first point */
2336   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2337   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2338   for (meetSize = 0; meetSize < dof; ++meetSize) {
2339     meet[i][meetSize] = mesh->cones[off+meetSize];
2340   }
2341   /* Check each successive cone */
2342   for (p = 1; p < numPoints; ++p) {
2343     PetscInt newMeetSize = 0;
2344 
2345     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2346     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2347     for (c = 0; c < dof; ++c) {
2348       const PetscInt point = mesh->cones[off+c];
2349 
2350       for (m = 0; m < meetSize; ++m) {
2351         if (point == meet[i][m]) {
2352           meet[1-i][newMeetSize++] = point;
2353           break;
2354         }
2355       }
2356     }
2357     meetSize = newMeetSize;
2358     i        = 1-i;
2359   }
2360   *numCoveringPoints = meetSize;
2361   *coveringPoints    = meet[i];
2362   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2363   PetscFunctionReturn(0);
2364 }
2365 
2366 #undef __FUNCT__
2367 #define __FUNCT__ "DMPlexRestoreMeet"
2368 /*@C
2369   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2370 
2371   Not Collective
2372 
2373   Input Parameters:
2374 + dm - The DMPlex object
2375 . numPoints - The number of input points for the meet
2376 - points - The input points
2377 
2378   Output Parameters:
2379 + numCoveredPoints - The number of points in the meet
2380 - coveredPoints - The points in the meet
2381 
2382   Level: intermediate
2383 
2384 .keywords: mesh
2385 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2386 @*/
2387 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2388 {
2389   PetscErrorCode ierr;
2390 
2391   PetscFunctionBegin;
2392   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2393   PetscValidPointer(coveredPoints, 4);
2394   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2395   PetscFunctionReturn(0);
2396 }
2397 
2398 #undef __FUNCT__
2399 #define __FUNCT__ "DMPlexGetFullMeet"
2400 /*@C
2401   DMPlexGetFullMeet - Get an array for the meet of the set of points
2402 
2403   Not Collective
2404 
2405   Input Parameters:
2406 + dm - The DMPlex object
2407 . numPoints - The number of input points for the meet
2408 - points - The input points
2409 
2410   Output Parameters:
2411 + numCoveredPoints - The number of points in the meet
2412 - coveredPoints - The points in the meet
2413 
2414   Level: intermediate
2415 
2416 .keywords: mesh
2417 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2418 @*/
2419 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2420 {
2421   DM_Plex       *mesh = (DM_Plex*) dm->data;
2422   PetscInt      *offsets, **closures;
2423   PetscInt      *meet[2];
2424   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2425   PetscInt       p, h, c, m;
2426   PetscErrorCode ierr;
2427 
2428   PetscFunctionBegin;
2429   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2430   PetscValidPointer(points, 2);
2431   PetscValidPointer(numCoveredPoints, 3);
2432   PetscValidPointer(coveredPoints, 4);
2433 
2434   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2435   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2436   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2437   maxSize = PetscPowInt(mesh->maxConeSize,height);
2438   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2439   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2440 
2441   for (p = 0; p < numPoints; ++p) {
2442     PetscInt closureSize;
2443 
2444     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2445 
2446     offsets[p*(height+2)+0] = 0;
2447     for (h = 0; h < height+1; ++h) {
2448       PetscInt pStart, pEnd, i;
2449 
2450       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2451       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2452         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2453           offsets[p*(height+2)+h+1] = i;
2454           break;
2455         }
2456       }
2457       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2458     }
2459     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2460   }
2461   for (h = 0; h < height+1; ++h) {
2462     PetscInt dof;
2463 
2464     /* Copy in cone of first point */
2465     dof = offsets[h+1] - offsets[h];
2466     for (meetSize = 0; meetSize < dof; ++meetSize) {
2467       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2468     }
2469     /* Check each successive cone */
2470     for (p = 1; p < numPoints && meetSize; ++p) {
2471       PetscInt newMeetSize = 0;
2472 
2473       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2474       for (c = 0; c < dof; ++c) {
2475         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2476 
2477         for (m = 0; m < meetSize; ++m) {
2478           if (point == meet[i][m]) {
2479             meet[1-i][newMeetSize++] = point;
2480             break;
2481           }
2482         }
2483       }
2484       meetSize = newMeetSize;
2485       i        = 1-i;
2486     }
2487     if (meetSize) break;
2488   }
2489   *numCoveredPoints = meetSize;
2490   *coveredPoints    = meet[i];
2491   for (p = 0; p < numPoints; ++p) {
2492     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2493   }
2494   ierr = PetscFree(closures);CHKERRQ(ierr);
2495   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2496   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2497   PetscFunctionReturn(0);
2498 }
2499 
2500 #undef __FUNCT__
2501 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2502 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2503 {
2504   MPI_Comm       comm = ((PetscObject) dm)->comm;
2505   PetscInt       cellDim;
2506   PetscErrorCode ierr;
2507 
2508   PetscFunctionBegin;
2509   PetscValidPointer(numFaceVertices,3);
2510   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2511   switch (cellDim) {
2512   case 0:
2513     *numFaceVertices = 0;
2514     break;
2515   case 1:
2516     *numFaceVertices = 1;
2517     break;
2518   case 2:
2519     switch (numCorners) {
2520     case 3: /* triangle */
2521       *numFaceVertices = 2; /* Edge has 2 vertices */
2522       break;
2523     case 4: /* quadrilateral */
2524       *numFaceVertices = 2; /* Edge has 2 vertices */
2525       break;
2526     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2527       *numFaceVertices = 3; /* Edge has 3 vertices */
2528       break;
2529     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2530       *numFaceVertices = 3; /* Edge has 3 vertices */
2531       break;
2532     default:
2533       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2534     }
2535     break;
2536   case 3:
2537     switch (numCorners) {
2538     case 4: /* tetradehdron */
2539       *numFaceVertices = 3; /* Face has 3 vertices */
2540       break;
2541     case 6: /* tet cohesive cells */
2542       *numFaceVertices = 4; /* Face has 4 vertices */
2543       break;
2544     case 8: /* hexahedron */
2545       *numFaceVertices = 4; /* Face has 4 vertices */
2546       break;
2547     case 9: /* tet cohesive Lagrange cells */
2548       *numFaceVertices = 6; /* Face has 6 vertices */
2549       break;
2550     case 10: /* quadratic tetrahedron */
2551       *numFaceVertices = 6; /* Face has 6 vertices */
2552       break;
2553     case 12: /* hex cohesive Lagrange cells */
2554       *numFaceVertices = 6; /* Face has 6 vertices */
2555       break;
2556     case 18: /* quadratic tet cohesive Lagrange cells */
2557       *numFaceVertices = 6; /* Face has 6 vertices */
2558       break;
2559     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2560       *numFaceVertices = 9; /* Face has 9 vertices */
2561       break;
2562     default:
2563       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2564     }
2565     break;
2566   default:
2567     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2568   }
2569   PetscFunctionReturn(0);
2570 }
2571 
2572 #undef __FUNCT__
2573 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2574 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2575 {
2576   const PetscInt maxFaceCases = 30;
2577   PetscInt       numFaceCases = 0;
2578   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2579   PetscInt      *off, *adj;
2580   PetscInt      *neighborCells, *tmpClosure;
2581   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2582   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2583   PetscErrorCode ierr;
2584 
2585   PetscFunctionBegin;
2586   /* For parallel partitioning, I think you have to communicate supports */
2587   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2588   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2589   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2590   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2591   if (cEnd - cStart == 0) {
2592     if (numVertices) *numVertices = 0;
2593     if (offsets)   *offsets   = PETSC_NULL;
2594     if (adjacency) *adjacency = PETSC_NULL;
2595     PetscFunctionReturn(0);
2596   }
2597   numCells = cEnd - cStart;
2598   /* Setup face recognition */
2599   if (depth == 1) {
2600     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 */
2601 
2602     for (c = cStart; c < cEnd; ++c) {
2603       PetscInt corners;
2604 
2605       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2606       if (!cornersSeen[corners]) {
2607         PetscInt nFV;
2608 
2609         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2610         cornersSeen[corners] = 1;
2611 
2612         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2613 
2614         numFaceVertices[numFaceCases++] = nFV;
2615       }
2616     }
2617   }
2618   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2619   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2620   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2621   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2622   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2623   /* Count neighboring cells */
2624   for (cell = cStart; cell < cEnd; ++cell) {
2625     PetscInt numNeighbors = maxNeighbors, n;
2626 
2627     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2628     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2629     for (n = 0; n < numNeighbors; ++n) {
2630       PetscInt        cellPair[2];
2631       PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2632       PetscInt        meetSize = 0;
2633       const PetscInt *meet    = PETSC_NULL;
2634 
2635       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2636       if (cellPair[0] == cellPair[1]) continue;
2637       if (!found) {
2638         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2639         if (meetSize) {
2640           PetscInt f;
2641 
2642           for (f = 0; f < numFaceCases; ++f) {
2643             if (numFaceVertices[f] == meetSize) {
2644               found = PETSC_TRUE;
2645               break;
2646             }
2647           }
2648         }
2649         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2650       }
2651       if (found) ++off[cell-cStart+1];
2652     }
2653   }
2654   /* Prefix sum */
2655   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2656 
2657   if (adjacency) {
2658     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2659     /* Get neighboring cells */
2660     for (cell = cStart; cell < cEnd; ++cell) {
2661       PetscInt numNeighbors = maxNeighbors, n;
2662       PetscInt cellOffset   = 0;
2663 
2664       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2665       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2666       for (n = 0; n < numNeighbors; ++n) {
2667         PetscInt        cellPair[2];
2668         PetscBool       found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2669         PetscInt        meetSize = 0;
2670         const PetscInt *meet    = PETSC_NULL;
2671 
2672         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2673         if (cellPair[0] == cellPair[1]) continue;
2674         if (!found) {
2675           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2676           if (meetSize) {
2677             PetscInt f;
2678 
2679             for (f = 0; f < numFaceCases; ++f) {
2680               if (numFaceVertices[f] == meetSize) {
2681                 found = PETSC_TRUE;
2682                 break;
2683               }
2684             }
2685           }
2686           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2687         }
2688         if (found) {
2689           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2690           ++cellOffset;
2691         }
2692       }
2693     }
2694   }
2695   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2696   if (numVertices) *numVertices = numCells;
2697   if (offsets)   *offsets   = off;
2698   if (adjacency) *adjacency = adj;
2699   PetscFunctionReturn(0);
2700 }
2701 
2702 #if defined(PETSC_HAVE_CHACO)
2703 #if defined(PETSC_HAVE_UNISTD_H)
2704 #include <unistd.h>
2705 #endif
2706 /* Chaco does not have an include file */
2707 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2708                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2709                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2710                        int mesh_dims[3], double *goal, int global_method, int local_method,
2711                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2712 
2713 extern int FREE_GRAPH;
2714 
2715 #undef __FUNCT__
2716 #define __FUNCT__ "DMPlexPartition_Chaco"
2717 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2718 {
2719   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2720   MPI_Comm       comm           = ((PetscObject) dm)->comm;
2721   int            nvtxs          = numVertices; /* number of vertices in full graph */
2722   int           *vwgts          = NULL;   /* weights for all vertices */
2723   float         *ewgts          = NULL;   /* weights for all edges */
2724   float         *x              = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2725   char          *outassignname  = NULL;   /*  name of assignment output file */
2726   char          *outfilename    = NULL;   /* output file name */
2727   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2728   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2729   int            mesh_dims[3];            /* dimensions of mesh of processors */
2730   double        *goal          = NULL;    /* desired set sizes for each set */
2731   int            global_method = 1;       /* global partitioning algorithm */
2732   int            local_method  = 1;       /* local partitioning algorithm */
2733   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2734   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2735   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2736   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2737   long           seed          = 123636512; /* for random graph mutations */
2738   short int     *assignment;              /* Output partition */
2739   int            fd_stdout, fd_pipe[2];
2740   PetscInt      *points;
2741   PetscMPIInt    commSize;
2742   int            i, v, p;
2743   PetscErrorCode ierr;
2744 
2745   PetscFunctionBegin;
2746   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2747   if (!numVertices) {
2748     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2749     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2750     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2751     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2752     PetscFunctionReturn(0);
2753   }
2754   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2755   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2756 
2757   if (global_method == INERTIAL_METHOD) {
2758     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2759     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2760   }
2761   mesh_dims[0] = commSize;
2762   mesh_dims[1] = 1;
2763   mesh_dims[2] = 1;
2764   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2765   /* Chaco outputs to stdout. We redirect this to a buffer. */
2766   /* TODO: check error codes for UNIX calls */
2767 #if defined(PETSC_HAVE_UNISTD_H)
2768   {
2769     int piperet;
2770     piperet = pipe(fd_pipe);
2771     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2772     fd_stdout = dup(1);
2773     close(1);
2774     dup2(fd_pipe[1], 1);
2775   }
2776 #endif
2777   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2778                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2779                    vmax, ndims, eigtol, seed);
2780 #if defined(PETSC_HAVE_UNISTD_H)
2781   {
2782     char msgLog[10000];
2783     int  count;
2784 
2785     fflush(stdout);
2786     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2787     if (count < 0) count = 0;
2788     msgLog[count] = 0;
2789     close(1);
2790     dup2(fd_stdout, 1);
2791     close(fd_stdout);
2792     close(fd_pipe[0]);
2793     close(fd_pipe[1]);
2794     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2795   }
2796 #endif
2797   /* Convert to PetscSection+IS */
2798   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2799   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2800   for (v = 0; v < nvtxs; ++v) {
2801     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2802   }
2803   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2804   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2805   for (p = 0, i = 0; p < commSize; ++p) {
2806     for (v = 0; v < nvtxs; ++v) {
2807       if (assignment[v] == p) points[i++] = v;
2808     }
2809   }
2810   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2811   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2812   if (global_method == INERTIAL_METHOD) {
2813     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2814   }
2815   ierr = PetscFree(assignment);CHKERRQ(ierr);
2816   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2817   PetscFunctionReturn(0);
2818 }
2819 #endif
2820 
2821 #if defined(PETSC_HAVE_PARMETIS)
2822 #undef __FUNCT__
2823 #define __FUNCT__ "DMPlexPartition_ParMetis"
2824 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2825 {
2826   PetscFunctionBegin;
2827   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2828   PetscFunctionReturn(0);
2829 }
2830 #endif
2831 
2832 #undef __FUNCT__
2833 #define __FUNCT__ "DMPlexEnlargePartition"
2834 /* Expand the partition by BFS on the adjacency graph */
2835 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2836 {
2837   PetscHashI      h;
2838   const PetscInt *points;
2839   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2840   PetscInt        pStart, pEnd, part, q;
2841   PetscErrorCode  ierr;
2842 
2843   PetscFunctionBegin;
2844   PetscHashICreate(h);
2845   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2846   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2847   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2848   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2849   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2850   for (part = pStart; part < pEnd; ++part) {
2851     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2852 
2853     PetscHashIClear(h);
2854     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2855     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2856     /* Add all existing points to h */
2857     for (p = 0; p < numPoints; ++p) {
2858       const PetscInt point = points[off+p];
2859       PetscHashIAdd(h, point, 1);
2860     }
2861     PetscHashISize(h, nP);
2862     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2863     /* Add all points in next BFS level */
2864     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2865     for (p = 0; p < numPoints; ++p) {
2866       const PetscInt point = points[off+p];
2867       PetscInt       s     = start[point], e = start[point+1], a;
2868 
2869       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2870     }
2871     PetscHashISize(h, numNewPoints);
2872     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2873     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2874     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2875     totPoints += numNewPoints;
2876   }
2877   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2878   PetscHashIDestroy(h);
2879   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2880   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2881   for (part = pStart, q = 0; part < pEnd; ++part) {
2882     PetscInt numPoints, p;
2883 
2884     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2885     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2886     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2887   }
2888   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2889   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2890   PetscFunctionReturn(0);
2891 }
2892 
2893 #undef __FUNCT__
2894 #define __FUNCT__ "DMPlexCreatePartition"
2895 /*
2896   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2897 
2898   Collective on DM
2899 
2900   Input Parameters:
2901   + dm - The DM
2902   . height - The height for points in the partition
2903   - enlarge - Expand each partition with neighbors
2904 
2905   Output Parameters:
2906   + partSection - The PetscSection giving the division of points by partition
2907   . partition - The list of points by partition
2908   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2909   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2910 
2911   Level: developer
2912 
2913 .seealso DMPlexDistribute()
2914 */
2915 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2916 {
2917   PetscMPIInt    size;
2918   PetscErrorCode ierr;
2919 
2920   PetscFunctionBegin;
2921   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2922 
2923   *origPartSection = PETSC_NULL;
2924   *origPartition   = PETSC_NULL;
2925   if (size == 1) {
2926     PetscInt *points;
2927     PetscInt  cStart, cEnd, c;
2928 
2929     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2930     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2931     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2932     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2933     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2934     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2935     for (c = cStart; c < cEnd; ++c) points[c] = c;
2936     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2937     PetscFunctionReturn(0);
2938   }
2939   if (height == 0) {
2940     PetscInt  numVertices;
2941     PetscInt *start     = PETSC_NULL;
2942     PetscInt *adjacency = PETSC_NULL;
2943 
2944     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2945     if (1) {
2946 #if defined(PETSC_HAVE_CHACO)
2947       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2948 #endif
2949     } else {
2950 #if defined(PETSC_HAVE_PARMETIS)
2951       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2952 #endif
2953     }
2954     if (enlarge) {
2955       *origPartSection = *partSection;
2956       *origPartition   = *partition;
2957 
2958       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2959     }
2960     ierr = PetscFree(start);CHKERRQ(ierr);
2961     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2962 # if 0
2963   } else if (height == 1) {
2964     /* Build the dual graph for faces and partition the hypergraph */
2965     PetscInt numEdges;
2966 
2967     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2968     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2969     destroyCSR(numEdges, start, adjacency);
2970 #endif
2971   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2972   PetscFunctionReturn(0);
2973 }
2974 
2975 #undef __FUNCT__
2976 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2977 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2978 {
2979   /* const PetscInt  height = 0; */
2980   const PetscInt *partArray;
2981   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2982   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2983   PetscErrorCode  ierr;
2984 
2985   PetscFunctionBegin;
2986   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2987   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2988   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2989   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2990   for (rank = rStart; rank < rEnd; ++rank) {
2991     PetscInt partSize = 0;
2992     PetscInt numPoints, offset, p;
2993 
2994     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2995     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2996     for (p = 0; p < numPoints; ++p) {
2997       PetscInt  point   = partArray[offset+p], closureSize, c;
2998       PetscInt *closure = PETSC_NULL;
2999 
3000       /* TODO Include support for height > 0 case */
3001       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3002       /* Merge into existing points */
3003       if (partSize+closureSize > maxPartSize) {
3004         PetscInt *tmpPoints;
3005 
3006         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3007         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3008         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3009         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3010 
3011         partPoints = tmpPoints;
3012       }
3013       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3014       partSize += closureSize;
3015 
3016       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3017       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3018     }
3019     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3020   }
3021   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3022   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3023   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3024 
3025   for (rank = rStart; rank < rEnd; ++rank) {
3026     PetscInt partSize = 0, newOffset;
3027     PetscInt numPoints, offset, p;
3028 
3029     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3030     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3031     for (p = 0; p < numPoints; ++p) {
3032       PetscInt  point   = partArray[offset+p], closureSize, c;
3033       PetscInt *closure = PETSC_NULL;
3034 
3035       /* TODO Include support for height > 0 case */
3036       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3037       /* Merge into existing points */
3038       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3039       partSize += closureSize;
3040 
3041       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3042       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3043     }
3044     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3045     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3046   }
3047   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3048   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3049   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3050   PetscFunctionReturn(0);
3051 }
3052 
3053 #undef __FUNCT__
3054 #define __FUNCT__ "DMPlexDistributeField"
3055 /*
3056   Input Parameters:
3057 . originalSection
3058 , originalVec
3059 
3060   Output Parameters:
3061 . newSection
3062 . newVec
3063 */
3064 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3065 {
3066   PetscSF        fieldSF;
3067   PetscInt      *remoteOffsets, fieldSize;
3068   PetscScalar   *originalValues, *newValues;
3069   PetscErrorCode ierr;
3070 
3071   PetscFunctionBegin;
3072   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3073 
3074   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3075   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3076   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3077 
3078   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3079   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3080   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3081   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3082   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3083   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3084   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3085   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3086   PetscFunctionReturn(0);
3087 }
3088 
3089 #undef __FUNCT__
3090 #define __FUNCT__ "DMPlexDistribute"
3091 /*@C
3092   DMPlexDistribute - Distributes the mesh and any associated sections.
3093 
3094   Not Collective
3095 
3096   Input Parameter:
3097 + dm  - The original DMPlex object
3098 . partitioner - The partitioning package, or NULL for the default
3099 - overlap - The overlap of partitions, 0 is the default
3100 
3101   Output Parameter:
3102 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3103 
3104   Note: If the mesh was not distributed, the return value is PETSC_NULL
3105 
3106   Level: intermediate
3107 
3108 .keywords: mesh, elements
3109 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3110 @*/
3111 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3112 {
3113   DM_Plex               *mesh   = (DM_Plex*) dm->data, *pmesh;
3114   MPI_Comm               comm   = ((PetscObject) dm)->comm;
3115   const PetscInt         height = 0;
3116   PetscInt               dim, numRemoteRanks;
3117   IS                     origCellPart,        cellPart,        part;
3118   PetscSection           origCellPartSection, cellPartSection, partSection;
3119   PetscSFNode           *remoteRanks;
3120   PetscSF                partSF, pointSF, coneSF;
3121   ISLocalToGlobalMapping renumbering;
3122   PetscSection           originalConeSection, newConeSection;
3123   PetscInt              *remoteOffsets;
3124   PetscInt              *cones, *newCones, newConesSize;
3125   PetscBool              flg;
3126   PetscMPIInt            rank, numProcs, p;
3127   PetscErrorCode         ierr;
3128 
3129   PetscFunctionBegin;
3130   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3131   PetscValidPointer(dmParallel,4);
3132 
3133   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3134   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3135   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3136 
3137   *dmParallel = PETSC_NULL;
3138   if (numProcs == 1) PetscFunctionReturn(0);
3139 
3140   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3141   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3142   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3143   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3144   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3145   if (!rank) numRemoteRanks = numProcs;
3146   else       numRemoteRanks = 0;
3147   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3148   for (p = 0; p < numRemoteRanks; ++p) {
3149     remoteRanks[p].rank  = p;
3150     remoteRanks[p].index = 0;
3151   }
3152   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3153   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3154   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3155   if (flg) {
3156     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3157     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3158     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3159     if (origCellPart) {
3160       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3161       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3162       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3163     }
3164     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3165   }
3166   /* Close the partition over the mesh */
3167   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3168   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3169   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3170   /* Create new mesh */
3171   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3172   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3173   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3174   pmesh = (DM_Plex*) (*dmParallel)->data;
3175   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3176   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3177   if (flg) {
3178     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3179     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3180     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3181     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3182     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3183     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3184   }
3185   /* Distribute cone section */
3186   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3187   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3188   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3189   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3190   {
3191     PetscInt pStart, pEnd, p;
3192 
3193     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3194     for (p = pStart; p < pEnd; ++p) {
3195       PetscInt coneSize;
3196       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3197       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3198     }
3199   }
3200   /* Communicate and renumber cones */
3201   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3202   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3203   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3204   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3205   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3206   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3207   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3208   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3209   if (flg) {
3210     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3211     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3212     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3213     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3214     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3215   }
3216   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3217   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3218   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3219   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3220   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3221   /* Create supports and stratify sieve */
3222   {
3223     PetscInt pStart, pEnd;
3224 
3225     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3226     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3227   }
3228   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3229   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3230   /* Distribute Coordinates */
3231   {
3232     PetscSection originalCoordSection, newCoordSection;
3233     Vec          originalCoordinates, newCoordinates;
3234     const char  *name;
3235 
3236     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3237     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3238     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3239     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3240     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3241     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3242 
3243     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3244     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3245     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3246   }
3247   /* Distribute labels */
3248   {
3249     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3250     PetscInt numLabels = 0, l;
3251 
3252     /* Bcast number of labels */
3253     while (next) {
3254       ++numLabels; next = next->next;
3255     }
3256     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3257     next = mesh->labels;
3258     for (l = 0; l < numLabels; ++l) {
3259       DMLabel         newLabel;
3260       const PetscInt *partArray;
3261       char           *name;
3262       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3263       PetscMPIInt    *sendcnts     = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3264       PetscInt        nameSize, s, p;
3265       PetscBool       isdepth;
3266       size_t          len = 0;
3267 
3268       /* Bcast name (could filter for no points) */
3269       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3270       nameSize = len;
3271       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3272       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3273       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3274       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3275       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3276       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3277       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3278       newLabel->name = name;
3279       /* Bcast numStrata (could filter for no points in stratum) */
3280       if (!rank) newLabel->numStrata = next->numStrata;
3281       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3282       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3283                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3284                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3285       /* Bcast stratumValues (could filter for no points in stratum) */
3286       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3287       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3288       /* Find size on each process and Scatter */
3289       if (!rank) {
3290         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3291         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3292         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3293         for (s = 0; s < next->numStrata; ++s) {
3294           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3295             const PetscInt point = next->points[p];
3296             PetscInt       proc;
3297 
3298             for (proc = 0; proc < numProcs; ++proc) {
3299               PetscInt dof, off, pPart;
3300 
3301               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3302               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3303               for (pPart = off; pPart < off+dof; ++pPart) {
3304                 if (partArray[pPart] == point) {
3305                   ++stratumSizes[proc*next->numStrata+s];
3306                   break;
3307                 }
3308               }
3309             }
3310           }
3311         }
3312         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3313       }
3314       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3315       /* Calculate stratumOffsets */
3316       newLabel->stratumOffsets[0] = 0;
3317       for (s = 0; s < newLabel->numStrata; ++s) {
3318         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3319       }
3320       /* Pack points and Scatter */
3321       if (!rank) {
3322         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3323         displs[0] = 0;
3324         for (p = 0; p < numProcs; ++p) {
3325           sendcnts[p] = 0;
3326           for (s = 0; s < next->numStrata; ++s) {
3327             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3328           }
3329           offsets[p]  = displs[p];
3330           displs[p+1] = displs[p] + sendcnts[p];
3331         }
3332         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3333         for (s = 0; s < next->numStrata; ++s) {
3334           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3335             const PetscInt point = next->points[p];
3336             PetscInt       proc;
3337 
3338             for (proc = 0; proc < numProcs; ++proc) {
3339               PetscInt dof, off, pPart;
3340 
3341               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3342               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3343               for (pPart = off; pPart < off+dof; ++pPart) {
3344                 if (partArray[pPart] == point) {
3345                   points[offsets[proc]++] = point;
3346                   break;
3347                 }
3348               }
3349             }
3350           }
3351         }
3352       }
3353       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3354       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3355       ierr = PetscFree(points);CHKERRQ(ierr);
3356       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3357       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3358       /* Renumber points */
3359       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3360       /* Sort points */
3361       for (s = 0; s < newLabel->numStrata; ++s) {
3362         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3363       }
3364       /* Insert into list */
3365       if (newNext) newNext->next = newLabel;
3366       else pmesh->labels = newLabel;
3367       newNext = newLabel;
3368       if (!rank) next = next->next;
3369     }
3370   }
3371   /* Cleanup Partition */
3372   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3373   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3374   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3375   ierr = ISDestroy(&part);CHKERRQ(ierr);
3376   /* Create point SF for parallel mesh */
3377   {
3378     const PetscInt *leaves;
3379     PetscSFNode    *remotePoints, *rowners, *lowners;
3380     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3381     PetscInt        pStart, pEnd;
3382 
3383     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3384     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3385     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3386     for (p=0; p<numRoots; p++) {
3387       rowners[p].rank  = -1;
3388       rowners[p].index = -1;
3389     }
3390     if (origCellPart) {
3391       /* Make sure cells in the original partition are not assigned to other procs */
3392       const PetscInt *origCells;
3393 
3394       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3395       for (p = 0; p < numProcs; ++p) {
3396         PetscInt dof, off, d;
3397 
3398         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3399         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3400         for (d = off; d < off+dof; ++d) {
3401           rowners[origCells[d]].rank = p;
3402         }
3403       }
3404       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3405     }
3406     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3407     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3408 
3409     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3410     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3411     for (p = 0; p < numLeaves; ++p) {
3412       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3413         lowners[p].rank  = rank;
3414         lowners[p].index = leaves ? leaves[p] : p;
3415       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3416         lowners[p].rank  = -2;
3417         lowners[p].index = -2;
3418       }
3419     }
3420     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3421       rowners[p].rank  = -3;
3422       rowners[p].index = -3;
3423     }
3424     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3425     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3426     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3427     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3428     for (p = 0; p < numLeaves; ++p) {
3429       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3430       if (lowners[p].rank != rank) ++numGhostPoints;
3431     }
3432     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3433     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3434     for (p = 0, gp = 0; p < numLeaves; ++p) {
3435       if (lowners[p].rank != rank) {
3436         ghostPoints[gp]        = leaves ? leaves[p] : p;
3437         remotePoints[gp].rank  = lowners[p].rank;
3438         remotePoints[gp].index = lowners[p].index;
3439         ++gp;
3440       }
3441     }
3442     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3443     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3444     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3445   }
3446   /* Cleanup */
3447   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3448   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3449   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3450   PetscFunctionReturn(0);
3451 }
3452 
3453 #undef __FUNCT__
3454 #define __FUNCT__ "DMPlexRenumber_Private"
3455 /*
3456   Reasons to renumber:
3457 
3458   1) Permute points, e.g. bandwidth reduction (Renumber)
3459 
3460     a) Must not mix strata
3461 
3462   2) Shift numbers for point insertion (Shift)
3463 
3464     a) Want operation brken into parts so that insertion can be interleaved
3465 
3466   renumbering - An IS which provides the new numbering
3467 */
3468 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3469 {
3470   PetscFunctionBegin;
3471   PetscFunctionReturn(0);
3472 }
3473 
3474 #undef __FUNCT__
3475 #define __FUNCT__ "DMPlexShiftPoint_Private"
3476 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3477 {
3478   if (depth < 0) return p;
3479   /* Cells    */ if (p < depthEnd[depth])   return p;
3480   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3481   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3482   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3483 }
3484 
3485 #undef __FUNCT__
3486 #define __FUNCT__ "DMPlexShiftSizes_Private"
3487 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3488 {
3489   PetscInt      *depthEnd;
3490   PetscInt       depth = 0, d, pStart, pEnd, p;
3491   PetscErrorCode ierr;
3492 
3493   PetscFunctionBegin;
3494   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3495   if (depth < 0) PetscFunctionReturn(0);
3496   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3497   /* Step 1: Expand chart */
3498   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3499   for (d = 0; d <= depth; ++d) {
3500     pEnd += depthShift[d];
3501     ierr  = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3502   }
3503   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3504   /* Step 2: Set cone and support sizes */
3505   for (d = 0; d <= depth; ++d) {
3506     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3507     for (p = pStart; p < pEnd; ++p) {
3508       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3509       PetscInt size;
3510 
3511       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3512       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3513       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3514       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3515     }
3516   }
3517   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3518   PetscFunctionReturn(0);
3519 }
3520 
3521 #undef __FUNCT__
3522 #define __FUNCT__ "DMPlexShiftPoints_Private"
3523 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3524 {
3525   PetscInt      *depthEnd, *newpoints;
3526   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3527   PetscErrorCode ierr;
3528 
3529   PetscFunctionBegin;
3530   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3531   if (depth < 0) PetscFunctionReturn(0);
3532   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3533   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3534   for (d = 0; d <= depth; ++d) {
3535     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3536   }
3537   /* Step 5: Set cones and supports */
3538   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3539   for (p = pStart; p < pEnd; ++p) {
3540     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3541     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3542 
3543     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3544     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3545     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3546     for (i = 0; i < size; ++i) {
3547       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3548     }
3549     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3550     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3551     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3552     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3553     for (i = 0; i < size; ++i) {
3554       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3555     }
3556     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3557   }
3558   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3559   PetscFunctionReturn(0);
3560 }
3561 
3562 #undef __FUNCT__
3563 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3564 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3565 {
3566   PetscSection   coordSection, newCoordSection;
3567   Vec            coordinates, newCoordinates;
3568   PetscScalar   *coords, *newCoords;
3569   PetscInt      *depthEnd, coordSize;
3570   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3571   PetscErrorCode ierr;
3572 
3573   PetscFunctionBegin;
3574   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3575   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3576   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3577   for (d = 0; d <= depth; ++d) {
3578     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3579   }
3580   /* Step 8: Convert coordinates */
3581   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3582   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3583   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3584   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3585   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3586   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3587   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3588   for (v = vStartNew; v < vEndNew; ++v) {
3589     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3590     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3591   }
3592   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3593   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3594   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3595   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3596   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3597   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3598   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3599   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3600   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3601   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3602   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3603   for (v = vStart; v < vEnd; ++v) {
3604     PetscInt dof, off, noff, d;
3605 
3606     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3607     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3608     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3609     for (d = 0; d < dof; ++d) {
3610       newCoords[noff+d] = coords[off+d];
3611     }
3612   }
3613   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3614   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3615   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3616   PetscFunctionReturn(0);
3617 }
3618 
3619 #undef __FUNCT__
3620 #define __FUNCT__ "DMPlexShiftSF_Private"
3621 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3622 {
3623   PetscInt          *depthEnd;
3624   PetscInt           depth = 0, d;
3625   PetscSF            sfPoint, sfPointNew;
3626   const PetscSFNode *remotePoints;
3627   PetscSFNode       *gremotePoints;
3628   const PetscInt    *localPoints;
3629   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3630   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3631   PetscMPIInt        numProcs;
3632   PetscErrorCode     ierr;
3633 
3634   PetscFunctionBegin;
3635   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3636   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3637   for (d = 0; d <= depth; ++d) {
3638     totShift += depthShift[d];
3639     ierr      = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3640   }
3641   /* Step 9: Convert pointSF */
3642   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3643   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3644   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3645   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3646   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3647   if (numRoots >= 0) {
3648     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3649     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3650     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3651     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3652     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3653     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3654     for (l = 0; l < numLeaves; ++l) {
3655       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3656       gremotePoints[l].rank  = remotePoints[l].rank;
3657       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3658     }
3659     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3660     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3661   }
3662   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3663   PetscFunctionReturn(0);
3664 }
3665 
3666 #undef __FUNCT__
3667 #define __FUNCT__ "DMPlexShiftLabels_Private"
3668 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3669 {
3670   PetscSF            sfPoint;
3671   DMLabel            vtkLabel, ghostLabel;
3672   PetscInt          *depthEnd;
3673   const PetscSFNode *leafRemote;
3674   const PetscInt    *leafLocal;
3675   PetscInt           depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3676   PetscMPIInt        rank;
3677   PetscErrorCode     ierr;
3678 
3679   PetscFunctionBegin;
3680   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3681   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3682   for (d = 0; d <= depth; ++d) {
3683     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3684   }
3685   /* Step 10: Convert labels */
3686   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3687   for (l = 0; l < numLabels; ++l) {
3688     DMLabel         label, newlabel;
3689     const char     *lname;
3690     PetscBool       isDepth;
3691     IS              valueIS;
3692     const PetscInt *values;
3693     PetscInt        numValues, val;
3694 
3695     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3696     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3697     if (isDepth) continue;
3698     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3699     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3700     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3701     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3702     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3703     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3704     for (val = 0; val < numValues; ++val) {
3705       IS              pointIS;
3706       const PetscInt *points;
3707       PetscInt        numPoints, p;
3708 
3709       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3710       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3711       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3712       for (p = 0; p < numPoints; ++p) {
3713         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3714 
3715         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3716       }
3717       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3718       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3719     }
3720     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3721     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3722   }
3723   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3724   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3725   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3726   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3727   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3728   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3729   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3730   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3731   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3732   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3733   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3734     for (; c < leafLocal[l] && c < cEnd; ++c) {
3735       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3736     }
3737     if (leafLocal[l] >= cEnd) break;
3738     if (leafRemote[l].rank == rank) {
3739       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3740     } else {
3741       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3742     }
3743   }
3744   for (; c < cEnd; ++c) {
3745     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3746   }
3747   if (0) {
3748     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3749     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3750     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3751   }
3752   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3753   for (f = fStart; f < fEnd; ++f) {
3754     PetscInt numCells;
3755 
3756     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3757     if (numCells < 2) {
3758       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3759     } else {
3760       const PetscInt *cells = PETSC_NULL;
3761       PetscInt        vA, vB;
3762 
3763       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3764       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3765       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3766       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3767     }
3768   }
3769   if (0) {
3770     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3771     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3772     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3773   }
3774   PetscFunctionReturn(0);
3775 }
3776 
3777 #undef __FUNCT__
3778 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3779 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3780 {
3781   DMLabel         label;
3782   IS              valueIS;
3783   const PetscInt *values;
3784   PetscInt       *depthShift;
3785   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3786   PetscErrorCode  ierr;
3787 
3788   PetscFunctionBegin;
3789   /* Count ghost cells */
3790   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3791   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3792   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3793   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3794 
3795   *numGhostCells = 0;
3796   for (fs = 0; fs < numFS; ++fs) {
3797     PetscInt numBdFaces;
3798 
3799     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3800 
3801     *numGhostCells += numBdFaces;
3802   }
3803   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3804   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3805   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3806   if (depth >= 0) depthShift[depth] = *numGhostCells;
3807   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3808   /* Step 3: Set cone/support sizes for new points */
3809   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3810   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3811     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3812   }
3813   for (fs = 0; fs < numFS; ++fs) {
3814     IS              faceIS;
3815     const PetscInt *faces;
3816     PetscInt        numFaces, f;
3817 
3818     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3819     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3820     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3821     for (f = 0; f < numFaces; ++f) {
3822       PetscInt size;
3823 
3824       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3825       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3826       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3827     }
3828     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3829     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3830   }
3831   /* Step 4: Setup ghosted DM */
3832   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3833   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3834   /* Step 6: Set cones and supports for new points */
3835   ghostCell = cEnd;
3836   for (fs = 0; fs < numFS; ++fs) {
3837     IS              faceIS;
3838     const PetscInt *faces;
3839     PetscInt        numFaces, f;
3840 
3841     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3842     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3843     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3844     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3845       PetscInt newFace = faces[f] + *numGhostCells;
3846 
3847       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3848       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3849     }
3850     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3851     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3852   }
3853   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3854   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3855   /* Step 7: Stratify */
3856   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3857   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3858   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3859   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3860   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3861   PetscFunctionReturn(0);
3862 }
3863 
3864 #undef __FUNCT__
3865 #define __FUNCT__ "DMPlexConstructGhostCells"
3866 /*@C
3867   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3868 
3869   Collective on dm
3870 
3871   Input Parameters:
3872 + dm - The original DM
3873 - labelName - The label specifying the boundary faces (this could be auto-generated)
3874 
3875   Output Parameters:
3876 + numGhostCells - The number of ghost cells added to the DM
3877 - dmGhosted - The new DM
3878 
3879   Level: developer
3880 
3881 .seealso: DMCreate()
3882 */
3883 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3884 {
3885   DM             gdm;
3886   PetscInt       dim;
3887   PetscErrorCode ierr;
3888 
3889   PetscFunctionBegin;
3890   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3891   PetscValidPointer(numGhostCells, 3);
3892   PetscValidPointer(dmGhosted, 4);
3893   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3894   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3895   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3896   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3897   switch (dim) {
3898   case 2:
3899     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3900     break;
3901   default:
3902     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3903   }
3904   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3905   *dmGhosted = gdm;
3906   PetscFunctionReturn(0);
3907 }
3908 
3909 #undef __FUNCT__
3910 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3911 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, const char labelName[], DM sdm)
3912 {
3913   MPI_Comm        comm = ((PetscObject) dm)->comm;
3914   DMLabel         label;
3915   IS              valueIS, *pointIS;
3916   const PetscInt *values, **splitPoints;
3917   PetscSection    coordSection;
3918   Vec             coordinates;
3919   PetscScalar    *coords;
3920   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3921   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3922   PetscErrorCode  ierr;
3923 
3924   PetscFunctionBegin;
3925   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3926   /* Count split points and add cohesive cells */
3927   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3928   if (label) {
3929     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3930     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3931     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3932   }
3933   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3934   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3935   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3936   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3937   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3938   for (d = 0; d <= depth; ++d) {
3939     ierr              = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3940     numSplitPoints[d] = 0;
3941     splitPoints[d]    = PETSC_NULL;
3942     pointIS[d]        = PETSC_NULL;
3943   }
3944   for (sp = 0; sp < numSP; ++sp) {
3945     const PetscInt dep = values[sp];
3946 
3947     if ((dep < 0) || (dep > depth)) continue;
3948     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3949     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3950     if (pointIS[dep]) {
3951       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3952       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3953     }
3954   }
3955   if (depth >= 0) {
3956     /* Calculate number of additional points */
3957     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3958     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3959     /* Calculate hybrid bound for each dimension */
3960     pMaxNew[0] += depthShift[depth];
3961     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3962     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3963 
3964     /* Calculate point offset for each dimension */
3965     depthOffset[depth] = 0;
3966     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3967     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3968     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3969   }
3970   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3971   /* Step 3: Set cone/support sizes for new points */
3972   for (dep = 0; dep <= depth; ++dep) {
3973     for (p = 0; p < numSplitPoints[dep]; ++p) {
3974       const PetscInt  oldp   = splitPoints[dep][p];
3975       const PetscInt  newp   = depthOffset[dep] + oldp;
3976       const PetscInt  splitp = pMaxNew[dep] + p;
3977       const PetscInt *support;
3978       PetscInt        coneSize, supportSize, q, e;
3979 
3980       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3981       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3982       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3983       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3984       if (dep == depth-1) {
3985         const PetscInt ccell = pMaxNew[depth] + p;
3986         /* Add cohesive cells, they are prisms */
3987         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3988       } else if (dep == 0) {
3989         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3990 
3991         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3992         /* Split old vertex: Edges in old split faces and new cohesive edge */
3993         for (e = 0, q = 0; e < supportSize; ++e) {
3994           PetscInt val;
3995 
3996           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3997           if ((val == 1) || (val == (shift + 1))) ++q;
3998         }
3999         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
4000         /* Split new vertex: Edges in new split faces and new cohesive edge */
4001         for (e = 0, q = 0; e < supportSize; ++e) {
4002           PetscInt val;
4003 
4004           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4005           if ((val == 1) || (val == -(shift + 1))) ++q;
4006         }
4007         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4008         /* Add cohesive edges */
4009         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4010         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4011       } else if (dep == dim-2) {
4012         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4013         /* Split old edge: Faces in positive side cells and old split faces */
4014         for (e = 0, q = 0; e < supportSize; ++e) {
4015           PetscInt val;
4016 
4017           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4018           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4019         }
4020         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4021         /* Split new edge: Faces in negative side cells and new split faces */
4022         for (e = 0, q = 0; e < supportSize; ++e) {
4023           PetscInt val;
4024 
4025           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4026           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4027         }
4028         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4029       }
4030     }
4031   }
4032   /* Step 4: Setup split DM */
4033   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4034   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4035   /* Step 6: Set cones and supports for new points */
4036   for (dep = 0; dep <= depth; ++dep) {
4037     for (p = 0; p < numSplitPoints[dep]; ++p) {
4038       const PetscInt  oldp   = splitPoints[dep][p];
4039       const PetscInt  newp   = depthOffset[dep] + oldp;
4040       const PetscInt  splitp = pMaxNew[dep] + p;
4041       const PetscInt *cone, *support, *ornt;
4042       PetscInt        coneSize, supportSize, q, v, e, s;
4043 
4044       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4045       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4046       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4047       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4048       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4049       if (dep == depth-1) {
4050         const PetscInt  ccell = pMaxNew[depth] + p;
4051         const PetscInt *supportF;
4052 
4053         /* Split face:       copy in old face to new face to start */
4054         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4055         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4056         /* Split old face:   old vertices/edges in cone so no change */
4057         /* Split new face:   new vertices/edges in cone */
4058         for (q = 0; q < coneSize; ++q) {
4059           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4060 
4061           coneNew[2+q] = pMaxNew[dim-2] + v;
4062         }
4063         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4064         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4065         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4066         coneNew[0] = newp;
4067         coneNew[1] = splitp;
4068         for (q = 0; q < coneSize; ++q) {
4069           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4070         }
4071         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4072 
4073 
4074         for (s = 0; s < supportSize; ++s) {
4075           PetscInt val;
4076 
4077           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4078           if (val < 0) {
4079             /* Split old face:   Replace negative side cell with cohesive cell */
4080             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4081           } else {
4082             /* Split new face:   Replace positive side cell with cohesive cell */
4083             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4084           }
4085         }
4086       } else if (dep == 0) {
4087         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4088 
4089         /* Split old vertex: Edges in old split faces and new cohesive edge */
4090         for (e = 0, q = 0; e < supportSize; ++e) {
4091           PetscInt val;
4092 
4093           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4094           if ((val == 1) || (val == (shift + 1))) {
4095             supportNew[q++] = depthOffset[1] + support[e];
4096           }
4097         }
4098         supportNew[q] = cedge;
4099 
4100         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4101         /* Split new vertex: Edges in new split faces and new cohesive edge */
4102         for (e = 0, q = 0; e < supportSize; ++e) {
4103           PetscInt val, edge;
4104 
4105           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4106           if (val == 1) {
4107             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4108             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4109             supportNew[q++] = pMaxNew[1] + edge;
4110           } else if (val == -(shift + 1)) {
4111             supportNew[q++] = depthOffset[1] + support[e];
4112           }
4113         }
4114         supportNew[q] = cedge;
4115         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4116         /* Cohesive edge:    Old and new split vertex, punting on support */
4117         coneNew[0] = newp;
4118         coneNew[1] = splitp;
4119         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4120       } else if (dep == dim-2) {
4121         /* Split old edge:   old vertices in cone so no change */
4122         /* Split new edge:   new vertices in cone */
4123         for (q = 0; q < coneSize; ++q) {
4124           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4125 
4126           coneNew[q] = pMaxNew[dim-3] + v;
4127         }
4128         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4129         /* Split old edge: Faces in positive side cells and old split faces */
4130         for (e = 0, q = 0; e < supportSize; ++e) {
4131           PetscInt val;
4132 
4133           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4134           if ((val == dim-1) || (val == (shift + dim-1))) {
4135             supportNew[q++] = depthOffset[dim-1] + support[e];
4136           }
4137         }
4138         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4139         /* Split new edge: Faces in negative side cells and new split faces */
4140         for(e = 0, q = 0; e < supportSize; ++e) {
4141           PetscInt val, face;
4142 
4143           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4144           if (val == dim-1) {
4145             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4146             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4147             supportNew[q++] = pMaxNew[dim-1] + face;
4148           } else if (val == -(shift + dim-1)) {
4149             supportNew[q++] = depthOffset[dim-1] + support[e];
4150           }
4151         }
4152         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4153       }
4154     }
4155   }
4156   /* Step 6b: Replace split points in negative side cones */
4157   for (sp = 0; sp < numSP; ++sp) {
4158     PetscInt        dep = values[sp];
4159     IS              pIS;
4160     PetscInt        numPoints;
4161     const PetscInt *points;
4162 
4163     if (dep >= 0) continue;
4164     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4165     if (!pIS) continue;
4166     dep  = -dep - shift;
4167     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4168     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4169     for (p = 0; p < numPoints; ++p) {
4170       const PetscInt  oldp = points[p];
4171       const PetscInt  newp = depthOffset[dep] + oldp;
4172       const PetscInt *cone;
4173       PetscInt        coneSize, c;
4174       PetscBool       replaced = PETSC_FALSE;
4175 
4176       /* Negative edge: replace split vertex */
4177       /* Negative cell: replace split face */
4178       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4179       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4180       for (c = 0; c < coneSize; ++c) {
4181         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4182         PetscInt       csplitp, cp, val;
4183 
4184         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4185         if (val == dep-1) {
4186           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4187           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4188           csplitp  = pMaxNew[dep-1] + cp;
4189           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4190           replaced = PETSC_TRUE;
4191         }
4192       }
4193       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4194     }
4195     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4196     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4197   }
4198   /* Step 7: Stratify */
4199   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4200   /* Step 8: Coordinates */
4201   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4202   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4203   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4204   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4205   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4206     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4207     const PetscInt splitp = pMaxNew[0] + v;
4208     PetscInt       dof, off, soff, d;
4209 
4210     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4211     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4212     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4213     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4214   }
4215   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4216   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4217   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4218   /* Step 10: Labels */
4219   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4220   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4221   for (dep = 0; dep <= depth; ++dep) {
4222     for (p = 0; p < numSplitPoints[dep]; ++p) {
4223       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4224       const PetscInt splitp = pMaxNew[dep] + p;
4225       PetscInt       l;
4226 
4227       for (l = 0; l < numLabels; ++l) {
4228         DMLabel     label;
4229         const char *lname;
4230         PetscInt    val;
4231 
4232         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4233         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4234         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4235         if (val >= 0) {
4236           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4237           if (dep == 0) {
4238             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4239             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4240           }
4241         }
4242       }
4243     }
4244   }
4245   for (sp = 0; sp < numSP; ++sp) {
4246     const PetscInt dep = values[sp];
4247 
4248     if ((dep < 0) || (dep > depth)) continue;
4249     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4250     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4251   }
4252   if (label) {
4253     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4254     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4255   }
4256   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4257   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4258   PetscFunctionReturn(0);
4259 }
4260 
4261 #undef __FUNCT__
4262 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4263 /*@C
4264   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4265 
4266   Collective on dm
4267 
4268   Input Parameters:
4269 + dm - The original DM
4270 - labelName - The label specifying the boundary faces (this could be auto-generated)
4271 
4272   Output Parameters:
4273 - dmSplit - The new DM
4274 
4275   Level: developer
4276 
4277 .seealso: DMCreate()
4278 */
4279 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4280 {
4281   DM             sdm;
4282   PetscInt       dim;
4283   PetscErrorCode ierr;
4284 
4285   PetscFunctionBegin;
4286   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4287   PetscValidPointer(dmSplit, 4);
4288   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4289   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4290   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4291   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4292   switch (dim) {
4293   case 2:
4294   case 3:
4295     ierr = DMPlexConstructCohesiveCells_Private(dm, labelName, sdm);CHKERRQ(ierr);
4296     break;
4297   default:
4298     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4299   }
4300   *dmSplit = sdm;
4301   PetscFunctionReturn(0);
4302 }
4303 
4304 #undef __FUNCT__
4305 #define __FUNCT__ "DMLabelCohesiveComplete"
4306 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4307 {
4308   IS              dimIS;
4309   const PetscInt *points;
4310   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4311   PetscErrorCode  ierr;
4312 
4313   PetscFunctionBegin;
4314   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4315   /* Cell orientation for face gives the side of the fault */
4316   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4317   if (!dimIS) PetscFunctionReturn(0);
4318   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4319   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4320   for (p = 0; p < numPoints; ++p) {
4321     const PetscInt *support;
4322     PetscInt        supportSize, s;
4323 
4324     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4325     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4326     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4327     for (s = 0; s < supportSize; ++s) {
4328       const PetscInt *cone, *ornt;
4329       PetscInt        coneSize, c;
4330       PetscBool       pos = PETSC_TRUE;
4331 
4332       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4333       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4334       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4335       for(c = 0; c < coneSize; ++c) {
4336         if (cone[c] == points[p]) {
4337           if (ornt[c] >= 0) {
4338             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4339           } else {
4340             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4341             pos  = PETSC_FALSE;
4342           }
4343           break;
4344         }
4345       }
4346       if (c == coneSize) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4347       /* Put faces touching the fault in the label */
4348       for (c = 0; c < coneSize; ++c) {
4349         const PetscInt point = cone[c];
4350 
4351         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4352         if (val == -1) {
4353           PetscInt *closure = PETSC_NULL;
4354           PetscInt  closureSize, cl;
4355 
4356           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4357           for (cl = 0; cl < closureSize*2; cl += 2) {
4358             const PetscInt clp = closure[cl];
4359 
4360             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4361             if ((val >= 0) && (val < dim-1)) {
4362               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4363               break;
4364             }
4365           }
4366           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4367         }
4368       }
4369     }
4370   }
4371   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4372   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4373   /* Search for other cells/faces/edges connected to the fault by a vertex */
4374   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4375   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4376   if (!dimIS) PetscFunctionReturn(0);
4377   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4378   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4379   for (p = 0; p < numPoints; ++p) {
4380     PetscInt *star = PETSC_NULL;
4381     PetscInt  starSize, s;
4382     PetscInt  again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4383 
4384     /* First mark cells connected to the fault */
4385     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4386     while (again) {
4387       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4388       again = 0;
4389       for (s = 0; s < starSize*2; s += 2) {
4390         const PetscInt  point = star[s];
4391         const PetscInt *cone;
4392         PetscInt        coneSize, c;
4393 
4394         if ((point < cStart) || (point >= cEnd)) continue;
4395         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4396         if (val != -1) continue;
4397         again = 2;
4398         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4399         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4400         for (c = 0; c < coneSize; ++c) {
4401           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4402           if (val != -1) {
4403             if (abs(val) < shift) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4404             if (val > 0) {
4405               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4406             } else {
4407               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4408             }
4409             again = 1;
4410             break;
4411           }
4412         }
4413       }
4414     }
4415     /* Classify the rest by cell membership */
4416     for (s = 0; s < starSize*2; s += 2) {
4417       const PetscInt point = star[s];
4418 
4419       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4420       if (val == -1) {
4421         PetscInt  *sstar = PETSC_NULL;
4422         PetscInt   sstarSize, ss;
4423         PetscBool  marked = PETSC_FALSE;
4424 
4425         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4426         for (ss = 0; ss < sstarSize*2; ss += 2) {
4427           const PetscInt spoint = sstar[ss];
4428 
4429           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4430           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4431           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4432           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4433           if (val > 0) {
4434             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4435           } else {
4436             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4437           }
4438           marked = PETSC_TRUE;
4439           break;
4440         }
4441         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4442         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4443       }
4444     }
4445     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4446   }
4447   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4448   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4449   PetscFunctionReturn(0);
4450 }
4451 
4452 #undef __FUNCT__
4453 #define __FUNCT__ "DMPlexInterpolate_2D"
4454 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4455 {
4456   DM             idm;
4457   DM_Plex       *mesh;
4458   PetscHashIJ    edgeTable;
4459   PetscInt      *off;
4460   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4461   PetscInt       numEdges, firstEdge, edge, e;
4462   PetscErrorCode ierr;
4463 
4464   PetscFunctionBegin;
4465   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4466   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4467   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4468   numCells    = cEnd - cStart;
4469   numVertices = vEnd - vStart;
4470   firstEdge   = numCells + numVertices;
4471   numEdges    = 0;
4472   /* Count edges using algorithm from CreateNeighborCSR */
4473   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4474   if (off) {
4475     PetscInt numCorners = 0;
4476 
4477     numEdges = off[numCells]/2;
4478 #if 0
4479     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4480     numEdges += 3*numCells - off[numCells];
4481 #else
4482     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4483     for (c = cStart; c < cEnd; ++c) {
4484       PetscInt coneSize;
4485 
4486       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4487       numCorners += coneSize;
4488     }
4489     numEdges += numCorners - off[numCells];
4490 #endif
4491   }
4492 #if 0
4493   /* Check Euler characteristic V - E + F = 1 */
4494   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4495 #endif
4496   /* Create interpolated mesh */
4497   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4498   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4499   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4500   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4501   for (c = 0; c < numCells; ++c) {
4502     PetscInt numCorners;
4503 
4504     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4505     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4506   }
4507   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4508     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4509   }
4510   ierr = DMSetUp(idm);CHKERRQ(ierr);
4511   /* Get edge cones from subsets of cell vertices */
4512   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4513   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4514 
4515   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4516     const PetscInt *cellFaces;
4517     PetscInt        numCellFaces, faceSize, cf;
4518 
4519     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4520     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4521     for (cf = 0; cf < numCellFaces; ++cf) {
4522 #if 1
4523       PetscHashIJKey key;
4524 
4525       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4526       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4527       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4528       if (e < 0) {
4529         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4530         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4531         e    = edge++;
4532       }
4533 #else
4534       PetscBool found = PETSC_FALSE;
4535 
4536       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4537       for (e = firstEdge; e < edge; ++e) {
4538         const PetscInt *cone;
4539 
4540         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4541         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4542             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4543           found = PETSC_TRUE;
4544           break;
4545         }
4546       }
4547       if (!found) {
4548         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4549         ++edge;
4550       }
4551 #endif
4552       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4553     }
4554   }
4555   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4556   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4557   ierr = PetscFree(off);CHKERRQ(ierr);
4558   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4559   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4560   mesh = (DM_Plex*) (idm)->data;
4561   /* Orient edges */
4562   for (c = 0; c < numCells; ++c) {
4563     const PetscInt *cone = PETSC_NULL, *cellFaces;
4564     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4565 
4566     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4567     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4568     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4569     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4570     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4571     for (cf = 0; cf < numCellFaces; ++cf) {
4572       const PetscInt *econe = PETSC_NULL;
4573       PetscInt        esize;
4574 
4575       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4576       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4577       if (esize != 2) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4578       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4579         /* Correctly oriented */
4580         mesh->coneOrientations[coff+cf] = 0;
4581       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4582         /* Start at index 1, and reverse orientation */
4583         mesh->coneOrientations[coff+cf] = -(1+1);
4584       }
4585     }
4586   }
4587   *dmInt = idm;
4588   PetscFunctionReturn(0);
4589 }
4590 
4591 #undef __FUNCT__
4592 #define __FUNCT__ "DMPlexInterpolate_3D"
4593 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4594 {
4595   DM             idm, fdm;
4596   DM_Plex       *mesh;
4597   PetscInt      *off;
4598   const PetscInt numCorners = 4;
4599   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4600   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4601   PetscErrorCode ierr;
4602 
4603   PetscFunctionBegin;
4604   {
4605     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4606     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4607     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4608   }
4609   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4610   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4611   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4612   numCells    = cEnd - cStart;
4613   numVertices = vEnd - vStart;
4614   firstFace   = numCells + numVertices;
4615   numFaces    = 0;
4616   /* Count faces using algorithm from CreateNeighborCSR */
4617   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4618   if (off) {
4619     numFaces = off[numCells]/2;
4620     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4621     numFaces += 4*numCells - off[numCells];
4622   }
4623   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4624   firstEdge = firstFace + numFaces;
4625   numEdges  = numVertices + numFaces - numCells - 1;
4626   /* Create interpolated mesh */
4627   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4628   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4629   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4630   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4631   for (c = 0; c < numCells; ++c) {
4632     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4633   }
4634   for (f = firstFace; f < firstFace+numFaces; ++f) {
4635     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4636   }
4637   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4638     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4639   }
4640   ierr = DMSetUp(idm);CHKERRQ(ierr);
4641   /* Get face cones from subsets of cell vertices */
4642   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4643   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4644   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4645   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4646   for (f = firstFace; f < firstFace+numFaces; ++f) {
4647     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4648   }
4649   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4650   for (c = 0, face = firstFace; c < numCells; ++c) {
4651     const PetscInt *cellFaces;
4652     PetscInt        numCellFaces, faceSize, cf;
4653 
4654     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4655     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4656     for (cf = 0; cf < numCellFaces; ++cf) {
4657       PetscBool found = PETSC_FALSE;
4658 
4659       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4660       for (f = firstFace; f < face; ++f) {
4661         const PetscInt *cone = PETSC_NULL;
4662 
4663         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4664         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4665             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4666             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4667             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4668             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4669             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4670           found = PETSC_TRUE;
4671           break;
4672         }
4673       }
4674       if (!found) {
4675         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4676         /* Save the vertices for orientation calculation */
4677         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4678         ++face;
4679       }
4680       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4681     }
4682   }
4683   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4684   /* Get edge cones from subsets of face vertices */
4685   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4686     const PetscInt *cellFaces;
4687     PetscInt        numCellFaces, faceSize, cf;
4688 
4689     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4690     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4691     for (cf = 0; cf < numCellFaces; ++cf) {
4692       PetscBool found = PETSC_FALSE;
4693 
4694       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4695       for (e = firstEdge; e < edge; ++e) {
4696         const PetscInt *cone = PETSC_NULL;
4697 
4698         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4699         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4700             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4701           found = PETSC_TRUE;
4702           break;
4703         }
4704       }
4705       if (!found) {
4706         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4707         ++edge;
4708       }
4709       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4710     }
4711   }
4712   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4713   ierr = PetscFree(off);CHKERRQ(ierr);
4714   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4715   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4716   mesh = (DM_Plex*) (idm)->data;
4717   /* Orient edges */
4718   for (f = firstFace; f < firstFace+numFaces; ++f) {
4719     const PetscInt *cone, *cellFaces;
4720     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4721 
4722     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4723     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4724     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4725     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4726     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4727     for (cf = 0; cf < numCellFaces; ++cf) {
4728       const PetscInt *econe;
4729       PetscInt        esize;
4730 
4731       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4732       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4733       if (esize != 2) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4734       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4735         /* Correctly oriented */
4736         mesh->coneOrientations[coff+cf] = 0;
4737       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4738         /* Start at index 1, and reverse orientation */
4739         mesh->coneOrientations[coff+cf] = -(1+1);
4740       }
4741     }
4742   }
4743   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4744   /* Orient faces */
4745   for (c = 0; c < numCells; ++c) {
4746     const PetscInt *cone, *cellFaces;
4747     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4748 
4749     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4750     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4751     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4752     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4753     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4754     for (cf = 0; cf < numCellFaces; ++cf) {
4755       PetscInt *origClosure = PETSC_NULL, *closure;
4756       PetscInt closureSize, i;
4757 
4758       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4759       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4760       for (i = 4; i < 7; ++i) {
4761         if ((origClosure[i*2] < vStart) || (origClosure[i*2] >= vEnd)) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure point %D should be a vertex in [%D, %D)", origClosure[i*2], vStart, vEnd);
4762       }
4763       closure = &origClosure[4*2];
4764       /* Remember that this is the orientation for edges, not vertices */
4765       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4766         /* Correctly oriented */
4767         mesh->coneOrientations[coff+cf] = 0;
4768       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4769         /* Shifted by 1 */
4770         mesh->coneOrientations[coff+cf] = 1;
4771       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4772         /* Shifted by 2 */
4773         mesh->coneOrientations[coff+cf] = 2;
4774       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4775         /* Start at edge 1, and reverse orientation */
4776         mesh->coneOrientations[coff+cf] = -(1+1);
4777       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4778         /* Start at index 0, and reverse orientation */
4779         mesh->coneOrientations[coff+cf] = -(0+1);
4780       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4781         /* Start at index 2, and reverse orientation */
4782         mesh->coneOrientations[coff+cf] = -(2+1);
4783       } else SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Face %D did not match local face %D in cell %D for any orientation", cone[cf], cf, c);
4784       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4785     }
4786   }
4787   {
4788     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4789     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4790     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4791   }
4792   *dmInt = idm;
4793   PetscFunctionReturn(0);
4794 }
4795 
4796 #undef __FUNCT__
4797 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4798 /*
4799   This takes as input the common mesh generator output, a list of the vertices for each cell
4800 */
4801 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4802 {
4803   PetscInt      *cone, c, p;
4804   PetscErrorCode ierr;
4805 
4806   PetscFunctionBegin;
4807   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4808   for (c = 0; c < numCells; ++c) {
4809     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4810   }
4811   ierr = DMSetUp(dm);CHKERRQ(ierr);
4812   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4813   for (c = 0; c < numCells; ++c) {
4814     for (p = 0; p < numCorners; ++p) {
4815       cone[p] = cells[c*numCorners+p]+numCells;
4816     }
4817     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4818   }
4819   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4820   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4821   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4822   PetscFunctionReturn(0);
4823 }
4824 
4825 #undef __FUNCT__
4826 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4827 /*
4828   This takes as input the coordinates for each vertex
4829 */
4830 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4831 {
4832   PetscSection   coordSection;
4833   Vec            coordinates;
4834   PetscScalar   *coords;
4835   PetscInt       coordSize, v, d;
4836   PetscErrorCode ierr;
4837 
4838   PetscFunctionBegin;
4839   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4840   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4841   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4842   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4843   for (v = numCells; v < numCells+numVertices; ++v) {
4844     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4845     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4846   }
4847   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4848   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4849   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4850   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4851   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4852   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4853   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4854   for (v = 0; v < numVertices; ++v) {
4855     for (d = 0; d < spaceDim; ++d) {
4856       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4857     }
4858   }
4859   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4860   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4861   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4862   PetscFunctionReturn(0);
4863 }
4864 
4865 #undef __FUNCT__
4866 #define __FUNCT__ "DMPlexCreateFromCellList"
4867 /*
4868   This takes as input the common mesh generator output, a list of the vertices for each cell
4869 */
4870 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4871 {
4872   PetscErrorCode ierr;
4873 
4874   PetscFunctionBegin;
4875   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4876   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4877   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4878   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4879   if (interpolate) {
4880     DM idm;
4881 
4882     switch (dim) {
4883     case 2:
4884       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4885     case 3:
4886       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4887     default:
4888       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4889     }
4890     ierr = DMDestroy(dm);CHKERRQ(ierr);
4891     *dm  = idm;
4892   }
4893   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4894   PetscFunctionReturn(0);
4895 }
4896 
4897 #if defined(PETSC_HAVE_TRIANGLE)
4898 #include <triangle.h>
4899 
4900 #undef __FUNCT__
4901 #define __FUNCT__ "InitInput_Triangle"
4902 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4903 {
4904   PetscFunctionBegin;
4905   inputCtx->numberofpoints             = 0;
4906   inputCtx->numberofpointattributes    = 0;
4907   inputCtx->pointlist                  = PETSC_NULL;
4908   inputCtx->pointattributelist         = PETSC_NULL;
4909   inputCtx->pointmarkerlist            = PETSC_NULL;
4910   inputCtx->numberofsegments           = 0;
4911   inputCtx->segmentlist                = PETSC_NULL;
4912   inputCtx->segmentmarkerlist          = PETSC_NULL;
4913   inputCtx->numberoftriangleattributes = 0;
4914   inputCtx->trianglelist               = PETSC_NULL;
4915   inputCtx->numberofholes              = 0;
4916   inputCtx->holelist                   = PETSC_NULL;
4917   inputCtx->numberofregions            = 0;
4918   inputCtx->regionlist                 = PETSC_NULL;
4919   PetscFunctionReturn(0);
4920 }
4921 
4922 #undef __FUNCT__
4923 #define __FUNCT__ "InitOutput_Triangle"
4924 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4925 {
4926   PetscFunctionBegin;
4927   outputCtx->numberofpoints        = 0;
4928   outputCtx->pointlist             = PETSC_NULL;
4929   outputCtx->pointattributelist    = PETSC_NULL;
4930   outputCtx->pointmarkerlist       = PETSC_NULL;
4931   outputCtx->numberoftriangles     = 0;
4932   outputCtx->trianglelist          = PETSC_NULL;
4933   outputCtx->triangleattributelist = PETSC_NULL;
4934   outputCtx->neighborlist          = PETSC_NULL;
4935   outputCtx->segmentlist           = PETSC_NULL;
4936   outputCtx->segmentmarkerlist     = PETSC_NULL;
4937   outputCtx->numberofedges         = 0;
4938   outputCtx->edgelist              = PETSC_NULL;
4939   outputCtx->edgemarkerlist        = PETSC_NULL;
4940   PetscFunctionReturn(0);
4941 }
4942 
4943 #undef __FUNCT__
4944 #define __FUNCT__ "FiniOutput_Triangle"
4945 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4946 {
4947   PetscFunctionBegin;
4948   free(outputCtx->pointmarkerlist);
4949   free(outputCtx->edgelist);
4950   free(outputCtx->edgemarkerlist);
4951   free(outputCtx->trianglelist);
4952   free(outputCtx->neighborlist);
4953   PetscFunctionReturn(0);
4954 }
4955 
4956 #undef __FUNCT__
4957 #define __FUNCT__ "DMPlexGenerate_Triangle"
4958 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4959 {
4960   MPI_Comm             comm             = ((PetscObject) boundary)->comm;
4961   PetscInt             dim              = 2;
4962   const PetscBool      createConvexHull = PETSC_FALSE;
4963   const PetscBool      constrained      = PETSC_FALSE;
4964   struct triangulateio in;
4965   struct triangulateio out;
4966   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4967   PetscMPIInt          rank;
4968   PetscErrorCode       ierr;
4969 
4970   PetscFunctionBegin;
4971   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4972   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4973   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4974   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4975 
4976   in.numberofpoints = vEnd - vStart;
4977   if (in.numberofpoints > 0) {
4978     PetscSection coordSection;
4979     Vec          coordinates;
4980     PetscScalar *array;
4981 
4982     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4983     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4984     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4985     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4986     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4987     for (v = vStart; v < vEnd; ++v) {
4988       const PetscInt idx = v - vStart;
4989       PetscInt       off, d;
4990 
4991       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4992       for (d = 0; d < dim; ++d) {
4993         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4994       }
4995       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4996     }
4997     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4998   }
4999   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
5000   in.numberofsegments = eEnd - eStart;
5001   if (in.numberofsegments > 0) {
5002     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
5003     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
5004     for (e = eStart; e < eEnd; ++e) {
5005       const PetscInt  idx = e - eStart;
5006       const PetscInt *cone;
5007 
5008       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
5009 
5010       in.segmentlist[idx*2+0] = cone[0] - vStart;
5011       in.segmentlist[idx*2+1] = cone[1] - vStart;
5012 
5013       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5014     }
5015   }
5016 #if 0 /* Do not currently support holes */
5017   PetscReal *holeCoords;
5018   PetscInt   h, d;
5019 
5020   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5021   if (in.numberofholes > 0) {
5022     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5023     for (h = 0; h < in.numberofholes; ++h) {
5024       for (d = 0; d < dim; ++d) {
5025         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5026       }
5027     }
5028   }
5029 #endif
5030   if (!rank) {
5031     char args[32];
5032 
5033     /* Take away 'Q' for verbose output */
5034     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5035     if (createConvexHull) {
5036       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5037     }
5038     if (constrained) {
5039       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5040     }
5041     triangulate(args, &in, &out, PETSC_NULL);
5042   }
5043   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5044   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5045   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5046   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5047   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5048 
5049   {
5050     const PetscInt numCorners  = 3;
5051     const PetscInt numCells    = out.numberoftriangles;
5052     const PetscInt numVertices = out.numberofpoints;
5053     const int     *cells      = out.trianglelist;
5054     const double  *meshCoords = out.pointlist;
5055 
5056     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5057     /* Set labels */
5058     for (v = 0; v < numVertices; ++v) {
5059       if (out.pointmarkerlist[v]) {
5060         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5061       }
5062     }
5063     if (interpolate) {
5064       for (e = 0; e < out.numberofedges; e++) {
5065         if (out.edgemarkerlist[e]) {
5066           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5067           const PetscInt *edges;
5068           PetscInt        numEdges;
5069 
5070           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5071           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5072           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5073           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5074         }
5075       }
5076     }
5077     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5078   }
5079 #if 0 /* Do not currently support holes */
5080   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5081 #endif
5082   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5083   PetscFunctionReturn(0);
5084 }
5085 
5086 #undef __FUNCT__
5087 #define __FUNCT__ "DMPlexRefine_Triangle"
5088 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5089 {
5090   MPI_Comm             comm = ((PetscObject) dm)->comm;
5091   PetscInt             dim  = 2;
5092   struct triangulateio in;
5093   struct triangulateio out;
5094   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5095   PetscMPIInt          rank;
5096   PetscErrorCode       ierr;
5097 
5098   PetscFunctionBegin;
5099   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5100   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5101   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5102   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5103   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5104   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5105 
5106   in.numberofpoints = vEnd - vStart;
5107   if (in.numberofpoints > 0) {
5108     PetscSection coordSection;
5109     Vec          coordinates;
5110     PetscScalar *array;
5111 
5112     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5113     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5114     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5115     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5116     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5117     for (v = vStart; v < vEnd; ++v) {
5118       const PetscInt idx = v - vStart;
5119       PetscInt       off, d;
5120 
5121       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5122       for (d = 0; d < dim; ++d) {
5123         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5124       }
5125       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5126     }
5127     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5128   }
5129   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5130 
5131   in.numberofcorners   = 3;
5132   in.numberoftriangles = cEnd - cStart;
5133 
5134   in.trianglearealist  = (double*) maxVolumes;
5135   if (in.numberoftriangles > 0) {
5136     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5137     for (c = cStart; c < cEnd; ++c) {
5138       const PetscInt idx      = c - cStart;
5139       PetscInt      *closure = PETSC_NULL;
5140       PetscInt       closureSize;
5141 
5142       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5143       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5144       for (v = 0; v < 3; ++v) {
5145         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5146       }
5147       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5148     }
5149   }
5150   /* TODO: Segment markers are missing on input */
5151 #if 0 /* Do not currently support holes */
5152   PetscReal *holeCoords;
5153   PetscInt   h, d;
5154 
5155   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5156   if (in.numberofholes > 0) {
5157     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5158     for (h = 0; h < in.numberofholes; ++h) {
5159       for (d = 0; d < dim; ++d) {
5160         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5161       }
5162     }
5163   }
5164 #endif
5165   if (!rank) {
5166     char args[32];
5167 
5168     /* Take away 'Q' for verbose output */
5169     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5170     triangulate(args, &in, &out, PETSC_NULL);
5171   }
5172   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5173   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5174   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5175   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5176   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5177 
5178   {
5179     const PetscInt numCorners  = 3;
5180     const PetscInt numCells    = out.numberoftriangles;
5181     const PetscInt numVertices = out.numberofpoints;
5182     const int     *cells      = out.trianglelist;
5183     const double  *meshCoords = out.pointlist;
5184     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5185 
5186     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5187     /* Set labels */
5188     for (v = 0; v < numVertices; ++v) {
5189       if (out.pointmarkerlist[v]) {
5190         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5191       }
5192     }
5193     if (interpolate) {
5194       PetscInt e;
5195 
5196       for (e = 0; e < out.numberofedges; e++) {
5197         if (out.edgemarkerlist[e]) {
5198           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5199           const PetscInt *edges;
5200           PetscInt        numEdges;
5201 
5202           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5203           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5204           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5205           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5206         }
5207       }
5208     }
5209     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5210   }
5211 #if 0 /* Do not currently support holes */
5212   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5213 #endif
5214   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5215   PetscFunctionReturn(0);
5216 }
5217 #endif
5218 
5219 #if defined(PETSC_HAVE_TETGEN)
5220 #include <tetgen.h>
5221 #undef __FUNCT__
5222 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5223 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5224 {
5225   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5226   const PetscInt dim  = 3;
5227   ::tetgenio     in;
5228   ::tetgenio     out;
5229   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5230   PetscMPIInt    rank;
5231   PetscErrorCode ierr;
5232 
5233   PetscFunctionBegin;
5234   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5235   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5236   in.numberofpoints = vEnd - vStart;
5237   if (in.numberofpoints > 0) {
5238     PetscSection coordSection;
5239     Vec          coordinates;
5240     PetscScalar *array;
5241 
5242     in.pointlist       = new double[in.numberofpoints*dim];
5243     in.pointmarkerlist = new int[in.numberofpoints];
5244 
5245     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5246     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5247     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5248     for (v = vStart; v < vEnd; ++v) {
5249       const PetscInt idx = v - vStart;
5250       PetscInt       off, d;
5251 
5252       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5253       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5254       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5255     }
5256     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5257   }
5258   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5259 
5260   in.numberoffacets = fEnd - fStart;
5261   if (in.numberoffacets > 0) {
5262     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5263     in.facetmarkerlist = new int[in.numberoffacets];
5264     for (f = fStart; f < fEnd; ++f) {
5265       const PetscInt idx     = f - fStart;
5266       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5267 
5268       in.facetlist[idx].numberofpolygons = 1;
5269       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5270       in.facetlist[idx].numberofholes    = 0;
5271       in.facetlist[idx].holelist         = NULL;
5272 
5273       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5274       for (p = 0; p < numPoints*2; p += 2) {
5275         const PetscInt point = points[p];
5276         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5277       }
5278 
5279       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5280       poly->numberofvertices = numVertices;
5281       poly->vertexlist       = new int[poly->numberofvertices];
5282       for (v = 0; v < numVertices; ++v) {
5283         const PetscInt vIdx = points[v] - vStart;
5284         poly->vertexlist[v] = vIdx;
5285       }
5286       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5287       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5288     }
5289   }
5290   if (!rank) {
5291     char args[32];
5292 
5293     /* Take away 'Q' for verbose output */
5294     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5295     ::tetrahedralize(args, &in, &out);
5296   }
5297   {
5298     const PetscInt numCorners  = 4;
5299     const PetscInt numCells    = out.numberoftetrahedra;
5300     const PetscInt numVertices = out.numberofpoints;
5301     const int     *cells      = out.tetrahedronlist;
5302     const double  *meshCoords = out.pointlist;
5303 
5304     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5305     /* Set labels */
5306     for (v = 0; v < numVertices; ++v) {
5307       if (out.pointmarkerlist[v]) {
5308         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5309       }
5310     }
5311     if (interpolate) {
5312       PetscInt e;
5313 
5314       for (e = 0; e < out.numberofedges; e++) {
5315         if (out.edgemarkerlist[e]) {
5316           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5317           const PetscInt *edges;
5318           PetscInt        numEdges;
5319 
5320           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5321           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5322           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5323           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5324         }
5325       }
5326       for (f = 0; f < out.numberoftrifaces; f++) {
5327         if (out.trifacemarkerlist[f]) {
5328           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5329           const PetscInt *faces;
5330           PetscInt        numFaces;
5331 
5332           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5333           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5334           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5335           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5336         }
5337       }
5338     }
5339     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5340   }
5341   PetscFunctionReturn(0);
5342 }
5343 
5344 #undef __FUNCT__
5345 #define __FUNCT__ "DMPlexRefine_Tetgen"
5346 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5347 {
5348   MPI_Comm       comm = ((PetscObject) dm)->comm;
5349   const PetscInt dim  = 3;
5350   ::tetgenio     in;
5351   ::tetgenio     out;
5352   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5353   PetscMPIInt    rank;
5354   PetscErrorCode ierr;
5355 
5356   PetscFunctionBegin;
5357   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5358   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5359   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5360   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5361 
5362   in.numberofpoints = vEnd - vStart;
5363   if (in.numberofpoints > 0) {
5364     PetscSection coordSection;
5365     Vec          coordinates;
5366     PetscScalar *array;
5367 
5368     in.pointlist       = new double[in.numberofpoints*dim];
5369     in.pointmarkerlist = new int[in.numberofpoints];
5370 
5371     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5372     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5373     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5374     for (v = vStart; v < vEnd; ++v) {
5375       const PetscInt idx = v - vStart;
5376       PetscInt       off, d;
5377 
5378       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5379       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5380       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5381     }
5382     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5383   }
5384   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5385 
5386   in.numberofcorners       = 4;
5387   in.numberoftetrahedra    = cEnd - cStart;
5388   in.tetrahedronvolumelist = (double*) maxVolumes;
5389   if (in.numberoftetrahedra > 0) {
5390     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5391     for (c = cStart; c < cEnd; ++c) {
5392       const PetscInt idx      = c - cStart;
5393       PetscInt      *closure = PETSC_NULL;
5394       PetscInt       closureSize;
5395 
5396       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5397       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5398       for (v = 0; v < 4; ++v) {
5399         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5400       }
5401       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5402     }
5403   }
5404   /* TODO: Put in boundary faces with markers */
5405   if (!rank) {
5406     char args[32];
5407 
5408     /* Take away 'Q' for verbose output */
5409     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5410     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5411     ::tetrahedralize(args, &in, &out);
5412   }
5413   in.tetrahedronvolumelist = NULL;
5414 
5415   {
5416     const PetscInt numCorners  = 4;
5417     const PetscInt numCells    = out.numberoftetrahedra;
5418     const PetscInt numVertices = out.numberofpoints;
5419     const int     *cells      = out.tetrahedronlist;
5420     const double  *meshCoords = out.pointlist;
5421     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5422 
5423     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5424     /* Set labels */
5425     for (v = 0; v < numVertices; ++v) {
5426       if (out.pointmarkerlist[v]) {
5427         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5428       }
5429     }
5430     if (interpolate) {
5431       PetscInt e, f;
5432 
5433       for (e = 0; e < out.numberofedges; e++) {
5434         if (out.edgemarkerlist[e]) {
5435           const PetscInt  vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5436           const PetscInt *edges;
5437           PetscInt        numEdges;
5438 
5439           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5440           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5441           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5442           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5443         }
5444       }
5445       for (f = 0; f < out.numberoftrifaces; f++) {
5446         if (out.trifacemarkerlist[f]) {
5447           const PetscInt  vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5448           const PetscInt *faces;
5449           PetscInt        numFaces;
5450 
5451           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5452           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5453           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5454           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5455         }
5456       }
5457     }
5458     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5459   }
5460   PetscFunctionReturn(0);
5461 }
5462 #endif
5463 
5464 #if defined(PETSC_HAVE_CTETGEN)
5465 #include "ctetgen.h"
5466 
5467 #undef __FUNCT__
5468 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5469 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5470 {
5471   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5472   const PetscInt dim  = 3;
5473   PLC           *in, *out;
5474   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5475   PetscMPIInt    rank;
5476   PetscErrorCode ierr;
5477 
5478   PetscFunctionBegin;
5479   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5480   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5481   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5482   ierr = PLCCreate(&in);CHKERRQ(ierr);
5483   ierr = PLCCreate(&out);CHKERRQ(ierr);
5484 
5485   in->numberofpoints = vEnd - vStart;
5486   if (in->numberofpoints > 0) {
5487     PetscSection coordSection;
5488     Vec          coordinates;
5489     PetscScalar *array;
5490 
5491     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5492     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5493     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5494     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5495     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5496     for (v = vStart; v < vEnd; ++v) {
5497       const PetscInt idx = v - vStart;
5498       PetscInt       off, d, m;
5499 
5500       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5501       for (d = 0; d < dim; ++d) {
5502         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5503       }
5504       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5505 
5506       in->pointmarkerlist[idx] = (int) m;
5507     }
5508     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5509   }
5510   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5511 
5512   in->numberoffacets = fEnd - fStart;
5513   if (in->numberoffacets > 0) {
5514     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5515     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5516     for (f = fStart; f < fEnd; ++f) {
5517       const PetscInt idx     = f - fStart;
5518       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5519       polygon       *poly;
5520 
5521       in->facetlist[idx].numberofpolygons = 1;
5522 
5523       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5524 
5525       in->facetlist[idx].numberofholes    = 0;
5526       in->facetlist[idx].holelist         = PETSC_NULL;
5527 
5528       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5529       for (p = 0; p < numPoints*2; p += 2) {
5530         const PetscInt point = points[p];
5531         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5532       }
5533 
5534       poly                   = in->facetlist[idx].polygonlist;
5535       poly->numberofvertices = numVertices;
5536       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5537       for (v = 0; v < numVertices; ++v) {
5538         const PetscInt vIdx = points[v] - vStart;
5539         poly->vertexlist[v] = vIdx;
5540       }
5541       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5542       in->facetmarkerlist[idx] = (int) m;
5543       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5544     }
5545   }
5546   if (!rank) {
5547     TetGenOpts t;
5548 
5549     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5550     t.in        = boundary; /* Should go away */
5551     t.plc       = 1;
5552     t.quality   = 1;
5553     t.edgesout  = 1;
5554     t.zeroindex = 1;
5555     t.quiet     = 1;
5556     t.verbose   = verbose;
5557     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5558     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5559   }
5560   {
5561     const PetscInt numCorners  = 4;
5562     const PetscInt numCells    = out->numberoftetrahedra;
5563     const PetscInt numVertices = out->numberofpoints;
5564     const int     *cells      = out->tetrahedronlist;
5565     const double  *meshCoords = out->pointlist;
5566 
5567     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5568     /* Set labels */
5569     for (v = 0; v < numVertices; ++v) {
5570       if (out->pointmarkerlist[v]) {
5571         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5572       }
5573     }
5574     if (interpolate) {
5575       PetscInt e;
5576 
5577       for (e = 0; e < out->numberofedges; e++) {
5578         if (out->edgemarkerlist[e]) {
5579           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5580           const PetscInt *edges;
5581           PetscInt        numEdges;
5582 
5583           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5584           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5585           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5586           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5587         }
5588       }
5589       for (f = 0; f < out->numberoftrifaces; f++) {
5590         if (out->trifacemarkerlist[f]) {
5591           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5592           const PetscInt *faces;
5593           PetscInt        numFaces;
5594 
5595           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5596           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5597           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5598           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5599         }
5600       }
5601     }
5602     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5603   }
5604 
5605   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5606   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5607   PetscFunctionReturn(0);
5608 }
5609 
5610 #undef __FUNCT__
5611 #define __FUNCT__ "DMPlexRefine_CTetgen"
5612 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5613 {
5614   MPI_Comm       comm = ((PetscObject) dm)->comm;
5615   const PetscInt dim  = 3;
5616   PLC           *in, *out;
5617   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5618   PetscMPIInt    rank;
5619   PetscErrorCode ierr;
5620 
5621   PetscFunctionBegin;
5622   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5623   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5624   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5625   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5626   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5627   ierr = PLCCreate(&in);CHKERRQ(ierr);
5628   ierr = PLCCreate(&out);CHKERRQ(ierr);
5629 
5630   in->numberofpoints = vEnd - vStart;
5631   if (in->numberofpoints > 0) {
5632     PetscSection coordSection;
5633     Vec          coordinates;
5634     PetscScalar *array;
5635 
5636     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5637     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5638     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5639     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5640     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5641     for (v = vStart; v < vEnd; ++v) {
5642       const PetscInt idx = v - vStart;
5643       PetscInt       off, d, m;
5644 
5645       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5646       for (d = 0; d < dim; ++d) {
5647         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5648       }
5649       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5650 
5651       in->pointmarkerlist[idx] = (int) m;
5652     }
5653     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5654   }
5655   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5656 
5657   in->numberofcorners       = 4;
5658   in->numberoftetrahedra    = cEnd - cStart;
5659   in->tetrahedronvolumelist = maxVolumes;
5660   if (in->numberoftetrahedra > 0) {
5661     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5662     for (c = cStart; c < cEnd; ++c) {
5663       const PetscInt idx      = c - cStart;
5664       PetscInt      *closure = PETSC_NULL;
5665       PetscInt       closureSize;
5666 
5667       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5668       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5669       for (v = 0; v < 4; ++v) {
5670         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5671       }
5672       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5673     }
5674   }
5675   if (!rank) {
5676     TetGenOpts t;
5677 
5678     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5679 
5680     t.in        = dm; /* Should go away */
5681     t.refine    = 1;
5682     t.varvolume = 1;
5683     t.quality   = 1;
5684     t.edgesout  = 1;
5685     t.zeroindex = 1;
5686     t.quiet     = 1;
5687     t.verbose   = verbose; /* Change this */
5688 
5689     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5690     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5691   }
5692   {
5693     const PetscInt numCorners  = 4;
5694     const PetscInt numCells    = out->numberoftetrahedra;
5695     const PetscInt numVertices = out->numberofpoints;
5696     const int     *cells       = out->tetrahedronlist;
5697     const double  *meshCoords  = out->pointlist;
5698     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5699 
5700     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5701     /* Set labels */
5702     for (v = 0; v < numVertices; ++v) {
5703       if (out->pointmarkerlist[v]) {
5704         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5705       }
5706     }
5707     if (interpolate) {
5708       PetscInt e, f;
5709 
5710       for (e = 0; e < out->numberofedges; e++) {
5711         if (out->edgemarkerlist[e]) {
5712           const PetscInt  vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5713           const PetscInt *edges;
5714           PetscInt        numEdges;
5715 
5716           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5717           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5718           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5719           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5720         }
5721       }
5722       for (f = 0; f < out->numberoftrifaces; f++) {
5723         if (out->trifacemarkerlist[f]) {
5724           const PetscInt  vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5725           const PetscInt *faces;
5726           PetscInt        numFaces;
5727 
5728           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5729           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5730           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5731           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5732         }
5733       }
5734     }
5735     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5736   }
5737   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5738   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5739   PetscFunctionReturn(0);
5740 }
5741 #endif
5742 
5743 #undef __FUNCT__
5744 #define __FUNCT__ "DMPlexGenerate"
5745 /*@C
5746   DMPlexGenerate - Generates a mesh.
5747 
5748   Not Collective
5749 
5750   Input Parameters:
5751 + boundary - The DMPlex boundary object
5752 . name - The mesh generation package name
5753 - interpolate - Flag to create intermediate mesh elements
5754 
5755   Output Parameter:
5756 . mesh - The DMPlex object
5757 
5758   Level: intermediate
5759 
5760 .keywords: mesh, elements
5761 .seealso: DMPlexCreate(), DMRefine()
5762 @*/
5763 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5764 {
5765   PetscInt       dim;
5766   char           genname[1024];
5767   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5768   PetscErrorCode ierr;
5769 
5770   PetscFunctionBegin;
5771   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5772   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5773   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5774   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5775   if (flg) name = genname;
5776   if (name) {
5777     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5778     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5779     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5780   }
5781   switch (dim) {
5782   case 1:
5783     if (!name || isTriangle) {
5784 #if defined(PETSC_HAVE_TRIANGLE)
5785       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5786 #else
5787       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5788 #endif
5789     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5790     break;
5791   case 2:
5792     if (!name || isCTetgen) {
5793 #if defined(PETSC_HAVE_CTETGEN)
5794       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5795 #else
5796       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5797 #endif
5798     } else if (isTetgen) {
5799 #if defined(PETSC_HAVE_TETGEN)
5800       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5801 #else
5802       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5803 #endif
5804     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5805     break;
5806   default:
5807     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5808   }
5809   PetscFunctionReturn(0);
5810 }
5811 
5812 typedef PetscInt CellRefiner;
5813 
5814 #undef __FUNCT__
5815 #define __FUNCT__ "GetDepthStart_Private"
5816 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5817 {
5818   PetscFunctionBegin;
5819   if (cStart) *cStart = 0;
5820   if (vStart) *vStart = depthSize[depth];
5821   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5822   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5823   PetscFunctionReturn(0);
5824 }
5825 
5826 #undef __FUNCT__
5827 #define __FUNCT__ "GetDepthEnd_Private"
5828 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5829 {
5830   PetscFunctionBegin;
5831   if (cEnd) *cEnd = depthSize[depth];
5832   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5833   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5834   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5835   PetscFunctionReturn(0);
5836 }
5837 
5838 #undef __FUNCT__
5839 #define __FUNCT__ "CellRefinerGetSizes"
5840 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5841 {
5842   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5843   PetscErrorCode ierr;
5844 
5845   PetscFunctionBegin;
5846   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5847   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5848   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5849   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5850   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5851   switch (refiner) {
5852   case 1:
5853     /* Simplicial 2D */
5854     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5855     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5856     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5857     break;
5858   case 3:
5859     /* Hybrid 2D */
5860     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5861     cMax = PetscMin(cEnd, cMax);
5862     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5863     fMax         = PetscMin(fEnd, fMax);
5864     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5865     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 */
5866     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5867     break;
5868   case 2:
5869     /* Hex 2D */
5870     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5871     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5872     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5873     break;
5874   default:
5875     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5876   }
5877   PetscFunctionReturn(0);
5878 }
5879 
5880 #undef __FUNCT__
5881 #define __FUNCT__ "CellRefinerSetConeSizes"
5882 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5883 {
5884   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5885   PetscErrorCode ierr;
5886 
5887   PetscFunctionBegin;
5888   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5889   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5890   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5891   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5892   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5893   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5894   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5895   switch (refiner) {
5896   case 1:
5897     /* Simplicial 2D */
5898     /* All cells have 3 faces */
5899     for (c = cStart; c < cEnd; ++c) {
5900       for (r = 0; r < 4; ++r) {
5901         const PetscInt newp = (c - cStart)*4 + r;
5902 
5903         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5904       }
5905     }
5906     /* Split faces have 2 vertices and the same cells as the parent */
5907     for (f = fStart; f < fEnd; ++f) {
5908       for (r = 0; r < 2; ++r) {
5909         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5910         PetscInt       size;
5911 
5912         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5913         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5914         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5915       }
5916     }
5917     /* Interior faces have 2 vertices and 2 cells */
5918     for (c = cStart; c < cEnd; ++c) {
5919       for (r = 0; r < 3; ++r) {
5920         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5921 
5922         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5923         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5924       }
5925     }
5926     /* Old vertices have identical supports */
5927     for (v = vStart; v < vEnd; ++v) {
5928       const PetscInt newp = vStartNew + (v - vStart);
5929       PetscInt       size;
5930 
5931       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5932       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5933     }
5934     /* Face vertices have 2 + cells*2 supports */
5935     for (f = fStart; f < fEnd; ++f) {
5936       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5937       PetscInt       size;
5938 
5939       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5940       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5941     }
5942     break;
5943   case 2:
5944     /* Hex 2D */
5945     /* All cells have 4 faces */
5946     for (c = cStart; c < cEnd; ++c) {
5947       for (r = 0; r < 4; ++r) {
5948         const PetscInt newp = (c - cStart)*4 + r;
5949 
5950         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5951       }
5952     }
5953     /* Split faces have 2 vertices and the same cells as the parent */
5954     for (f = fStart; f < fEnd; ++f) {
5955       for (r = 0; r < 2; ++r) {
5956         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5957         PetscInt       size;
5958 
5959         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5960         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5961         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5962       }
5963     }
5964     /* Interior faces have 2 vertices and 2 cells */
5965     for (c = cStart; c < cEnd; ++c) {
5966       for (r = 0; r < 4; ++r) {
5967         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5968 
5969         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5970         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5971       }
5972     }
5973     /* Old vertices have identical supports */
5974     for (v = vStart; v < vEnd; ++v) {
5975       const PetscInt newp = vStartNew + (v - vStart);
5976       PetscInt       size;
5977 
5978       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5979       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5980     }
5981     /* Face vertices have 2 + cells supports */
5982     for (f = fStart; f < fEnd; ++f) {
5983       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5984       PetscInt       size;
5985 
5986       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5987       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5988     }
5989     /* Cell vertices have 4 supports */
5990     for (c = cStart; c < cEnd; ++c) {
5991       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5992 
5993       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5994     }
5995     break;
5996   case 3:
5997     /* Hybrid 2D */
5998     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5999     cMax = PetscMin(cEnd, cMax);
6000     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6001     fMax = PetscMin(fEnd, fMax);
6002     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6003     /* Interior cells have 3 faces */
6004     for (c = cStart; c < cMax; ++c) {
6005       for (r = 0; r < 4; ++r) {
6006         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
6007 
6008         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
6009       }
6010     }
6011     /* Hybrid cells have 4 faces */
6012     for (c = cMax; c < cEnd; ++c) {
6013       for (r = 0; r < 2; ++r) {
6014         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6015 
6016         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6017       }
6018     }
6019     /* Interior split faces have 2 vertices and the same cells as the parent */
6020     for (f = fStart; f < fMax; ++f) {
6021       for (r = 0; r < 2; ++r) {
6022         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6023         PetscInt       size;
6024 
6025         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6026         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6027         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6028       }
6029     }
6030     /* Interior cell faces have 2 vertices and 2 cells */
6031     for (c = cStart; c < cMax; ++c) {
6032       for (r = 0; r < 3; ++r) {
6033         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6034 
6035         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6036         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6037       }
6038     }
6039     /* Hybrid faces have 2 vertices and the same cells */
6040     for (f = fMax; f < fEnd; ++f) {
6041       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6042       PetscInt       size;
6043 
6044       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6045       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6046       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6047     }
6048     /* Hybrid cell faces have 2 vertices and 2 cells */
6049     for (c = cMax; c < cEnd; ++c) {
6050       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6051 
6052       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6053       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6054     }
6055     /* Old vertices have identical supports */
6056     for (v = vStart; v < vEnd; ++v) {
6057       const PetscInt newp = vStartNew + (v - vStart);
6058       PetscInt       size;
6059 
6060       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6061       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6062     }
6063     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6064     for (f = fStart; f < fMax; ++f) {
6065       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6066       const PetscInt *support;
6067       PetscInt       size, newSize = 2, s;
6068 
6069       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6070       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6071       for (s = 0; s < size; ++s) {
6072         if (support[s] >= cMax) newSize += 1;
6073         else newSize += 2;
6074       }
6075       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6076     }
6077     break;
6078   default:
6079     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6080   }
6081   PetscFunctionReturn(0);
6082 }
6083 
6084 #undef __FUNCT__
6085 #define __FUNCT__ "CellRefinerSetCones"
6086 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6087 {
6088   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;
6089   PetscInt       maxSupportSize, *supportRef;
6090   PetscErrorCode ierr;
6091 
6092   PetscFunctionBegin;
6093   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6094   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6095   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6096   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6097   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6098   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6099   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6100   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6101   switch (refiner) {
6102   case 1:
6103     /* Simplicial 2D */
6104     /*
6105      2
6106      |\
6107      | \
6108      |  \
6109      |   \
6110      | C  \
6111      |     \
6112      |      \
6113      2---1---1
6114      |\  D  / \
6115      | 2   0   \
6116      |A \ /  B  \
6117      0---0-------1
6118      */
6119     /* All cells have 3 faces */
6120     for (c = cStart; c < cEnd; ++c) {
6121       const PetscInt  newp = cStartNew + (c - cStart)*4;
6122       const PetscInt *cone, *ornt;
6123       PetscInt        coneNew[3], orntNew[3];
6124 
6125       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6126       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6127       /* A triangle */
6128       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6129       orntNew[0] = ornt[0];
6130       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6131       orntNew[1] = -2;
6132       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6133       orntNew[2] = ornt[2];
6134       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6135       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6136 #if 1
6137       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6138       for (p = 0; p < 3; ++p) {
6139         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6140       }
6141 #endif
6142       /* B triangle */
6143       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6144       orntNew[0] = ornt[0];
6145       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6146       orntNew[1] = ornt[1];
6147       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6148       orntNew[2] = -2;
6149       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6150       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6151 #if 1
6152       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6153       for (p = 0; p < 3; ++p) {
6154         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6155       }
6156 #endif
6157       /* C triangle */
6158       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6159       orntNew[0] = -2;
6160       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6161       orntNew[1] = ornt[1];
6162       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6163       orntNew[2] = ornt[2];
6164       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6165       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6166 #if 1
6167       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6168       for (p = 0; p < 3; ++p) {
6169         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6170       }
6171 #endif
6172       /* D triangle */
6173       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6174       orntNew[0] = 0;
6175       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6176       orntNew[1] = 0;
6177       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6178       orntNew[2] = 0;
6179       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6180       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6181 #if 1
6182       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6183       for (p = 0; p < 3; ++p) {
6184         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6185       }
6186 #endif
6187     }
6188     /* Split faces have 2 vertices and the same cells as the parent */
6189     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6190     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6191     for (f = fStart; f < fEnd; ++f) {
6192       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6193 
6194       for (r = 0; r < 2; ++r) {
6195         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6196         const PetscInt *cone, *support;
6197         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6198 
6199         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6200         coneNew[0]       = vStartNew + (cone[0] - vStart);
6201         coneNew[1]       = vStartNew + (cone[1] - vStart);
6202         coneNew[(r+1)%2] = newv;
6203         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6204 #if 1
6205         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6206         for (p = 0; p < 2; ++p) {
6207           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6208         }
6209 #endif
6210         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6211         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6212         for (s = 0; s < supportSize; ++s) {
6213           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6214           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6215           for (c = 0; c < coneSize; ++c) {
6216             if (cone[c] == f) break;
6217           }
6218           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6219         }
6220         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6221 #if 1
6222         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6223         for (p = 0; p < supportSize; ++p) {
6224           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6225         }
6226 #endif
6227       }
6228     }
6229     /* Interior faces have 2 vertices and 2 cells */
6230     for (c = cStart; c < cEnd; ++c) {
6231       const PetscInt *cone;
6232 
6233       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6234       for (r = 0; r < 3; ++r) {
6235         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6236         PetscInt       coneNew[2];
6237         PetscInt       supportNew[2];
6238 
6239         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6240         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6241         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6242 #if 1
6243         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6244         for (p = 0; p < 2; ++p) {
6245           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6246         }
6247 #endif
6248         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6249         supportNew[1] = (c - cStart)*4 + 3;
6250         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6251 #if 1
6252         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6253         for (p = 0; p < 2; ++p) {
6254           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6255         }
6256 #endif
6257       }
6258     }
6259     /* Old vertices have identical supports */
6260     for (v = vStart; v < vEnd; ++v) {
6261       const PetscInt  newp = vStartNew + (v - vStart);
6262       const PetscInt *support, *cone;
6263       PetscInt        size, s;
6264 
6265       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6266       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6267       for (s = 0; s < size; ++s) {
6268         PetscInt r = 0;
6269 
6270         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6271         if (cone[1] == v) r = 1;
6272         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6273       }
6274       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6275 #if 1
6276       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6277       for (p = 0; p < size; ++p) {
6278         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6279       }
6280 #endif
6281     }
6282     /* Face vertices have 2 + cells*2 supports */
6283     for (f = fStart; f < fEnd; ++f) {
6284       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6285       const PetscInt *cone, *support;
6286       PetscInt        size, s;
6287 
6288       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6289       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6290       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6291       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6292       for (s = 0; s < size; ++s) {
6293         PetscInt r = 0;
6294 
6295         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6296         if      (cone[1] == f) r = 1;
6297         else if (cone[2] == f) r = 2;
6298         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6299         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6300       }
6301       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6302 #if 1
6303       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6304       for (p = 0; p < 2+size*2; ++p) {
6305         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6306       }
6307 #endif
6308     }
6309     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6310     break;
6311   case 2:
6312     /* Hex 2D */
6313     /*
6314      3---------2---------2
6315      |         |         |
6316      |    D    2    C    |
6317      |         |         |
6318      3----3----0----1----1
6319      |         |         |
6320      |    A    0    B    |
6321      |         |         |
6322      0---------0---------1
6323      */
6324     /* All cells have 4 faces */
6325     for (c = cStart; c < cEnd; ++c) {
6326       const PetscInt  newp = (c - cStart)*4;
6327       const PetscInt *cone, *ornt;
6328       PetscInt        coneNew[4], orntNew[4];
6329 
6330       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6331       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6332       /* A quad */
6333       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6334       orntNew[0] = ornt[0];
6335       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6336       orntNew[1] = 0;
6337       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6338       orntNew[2] = -2;
6339       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6340       orntNew[3] = ornt[3];
6341       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6342       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6343 #if 1
6344       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6345       for (p = 0; p < 4; ++p) {
6346         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6347       }
6348 #endif
6349       /* B quad */
6350       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6351       orntNew[0] = ornt[0];
6352       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6353       orntNew[1] = ornt[1];
6354       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6355       orntNew[2] = 0;
6356       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6357       orntNew[3] = -2;
6358       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6359       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6360 #if 1
6361       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6362       for (p = 0; p < 4; ++p) {
6363         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6364       }
6365 #endif
6366       /* C quad */
6367       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6368       orntNew[0] = -2;
6369       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6370       orntNew[1] = ornt[1];
6371       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6372       orntNew[2] = ornt[2];
6373       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6374       orntNew[3] = 0;
6375       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6376       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6377 #if 1
6378       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6379       for (p = 0; p < 4; ++p) {
6380         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6381       }
6382 #endif
6383       /* D quad */
6384       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6385       orntNew[0] = 0;
6386       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6387       orntNew[1] = -2;
6388       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6389       orntNew[2] = ornt[2];
6390       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6391       orntNew[3] = ornt[3];
6392       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6393       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6394 #if 1
6395       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6396       for (p = 0; p < 4; ++p) {
6397         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6398       }
6399 #endif
6400     }
6401     /* Split faces have 2 vertices and the same cells as the parent */
6402     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6403     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6404     for (f = fStart; f < fEnd; ++f) {
6405       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6406 
6407       for (r = 0; r < 2; ++r) {
6408         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6409         const PetscInt *cone, *support;
6410         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6411 
6412         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6413         coneNew[0]       = vStartNew + (cone[0] - vStart);
6414         coneNew[1]       = vStartNew + (cone[1] - vStart);
6415         coneNew[(r+1)%2] = newv;
6416         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6417 #if 1
6418         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6419         for (p = 0; p < 2; ++p) {
6420           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6421         }
6422 #endif
6423         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6424         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6425         for (s = 0; s < supportSize; ++s) {
6426           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6427           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6428           for (c = 0; c < coneSize; ++c) {
6429             if (cone[c] == f) break;
6430           }
6431           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6432         }
6433         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6434 #if 1
6435         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6436         for (p = 0; p < supportSize; ++p) {
6437           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6438         }
6439 #endif
6440       }
6441     }
6442     /* Interior faces have 2 vertices and 2 cells */
6443     for (c = cStart; c < cEnd; ++c) {
6444       const PetscInt *cone;
6445       PetscInt        coneNew[2], supportNew[2];
6446 
6447       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6448       for (r = 0; r < 4; ++r) {
6449         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6450 
6451         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6452         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6453         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6454 #if 1
6455         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6456         for (p = 0; p < 2; ++p) {
6457           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6458         }
6459 #endif
6460         supportNew[0] = (c - cStart)*4 + r;
6461         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6462         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6463 #if 1
6464         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6465         for (p = 0; p < 2; ++p) {
6466           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6467         }
6468 #endif
6469       }
6470     }
6471     /* Old vertices have identical supports */
6472     for (v = vStart; v < vEnd; ++v) {
6473       const PetscInt  newp = vStartNew + (v - vStart);
6474       const PetscInt *support, *cone;
6475       PetscInt        size, s;
6476 
6477       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6478       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6479       for (s = 0; s < size; ++s) {
6480         PetscInt r = 0;
6481 
6482         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6483         if (cone[1] == v) r = 1;
6484         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6485       }
6486       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6487 #if 1
6488       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6489       for (p = 0; p < size; ++p) {
6490         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6491       }
6492 #endif
6493     }
6494     /* Face vertices have 2 + cells supports */
6495     for (f = fStart; f < fEnd; ++f) {
6496       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6497       const PetscInt *cone, *support;
6498       PetscInt        size, s;
6499 
6500       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6501       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6502       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6503       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6504       for (s = 0; s < size; ++s) {
6505         PetscInt r = 0;
6506 
6507         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6508         if      (cone[1] == f) r = 1;
6509         else if (cone[2] == f) r = 2;
6510         else if (cone[3] == f) r = 3;
6511         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6512       }
6513       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6514 #if 1
6515       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6516       for (p = 0; p < 2+size; ++p) {
6517         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6518       }
6519 #endif
6520     }
6521     /* Cell vertices have 4 supports */
6522     for (c = cStart; c < cEnd; ++c) {
6523       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6524       PetscInt       supportNew[4];
6525 
6526       for (r = 0; r < 4; ++r) {
6527         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6528       }
6529       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6530     }
6531     break;
6532   case 3:
6533     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6534     cMax = PetscMin(cEnd, cMax);
6535     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6536     fMax = PetscMin(fEnd, fMax);
6537     /* Interior cells have 3 faces */
6538     for (c = cStart; c < cMax; ++c) {
6539       const PetscInt  newp = cStartNew + (c - cStart)*4;
6540       const PetscInt *cone, *ornt;
6541       PetscInt        coneNew[3], orntNew[3];
6542 
6543       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6544       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6545       /* A triangle */
6546       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6547       orntNew[0] = ornt[0];
6548       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6549       orntNew[1] = -2;
6550       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6551       orntNew[2] = ornt[2];
6552       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6553       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6554 #if 1
6555       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6556       for (p = 0; p < 3; ++p) {
6557         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6558       }
6559 #endif
6560       /* B triangle */
6561       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6562       orntNew[0] = ornt[0];
6563       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6564       orntNew[1] = ornt[1];
6565       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6566       orntNew[2] = -2;
6567       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6568       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6569 #if 1
6570       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6571       for (p = 0; p < 3; ++p) {
6572         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6573       }
6574 #endif
6575       /* C triangle */
6576       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6577       orntNew[0] = -2;
6578       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6579       orntNew[1] = ornt[1];
6580       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6581       orntNew[2] = ornt[2];
6582       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6583       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6584 #if 1
6585       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6586       for (p = 0; p < 3; ++p) {
6587         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6588       }
6589 #endif
6590       /* D triangle */
6591       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6592       orntNew[0] = 0;
6593       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6594       orntNew[1] = 0;
6595       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6596       orntNew[2] = 0;
6597       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6598       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6599 #if 1
6600       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6601       for (p = 0; p < 3; ++p) {
6602         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6603       }
6604 #endif
6605     }
6606     /*
6607      2----3----3
6608      |         |
6609      |    B    |
6610      |         |
6611      0----4--- 1
6612      |         |
6613      |    A    |
6614      |         |
6615      0----2----1
6616      */
6617     /* Hybrid cells have 4 faces */
6618     for (c = cMax; c < cEnd; ++c) {
6619       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6620       const PetscInt *cone, *ornt;
6621       PetscInt        coneNew[4], orntNew[4];
6622 
6623       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6624       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6625       /* A quad */
6626       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6627       orntNew[0] = ornt[0];
6628       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6629       orntNew[1] = ornt[1];
6630       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6631       orntNew[2] = 0;
6632       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6633       orntNew[3] = 0;
6634       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6635       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6636 #if 1
6637       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6638       for (p = 0; p < 4; ++p) {
6639         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6640       }
6641 #endif
6642       /* B quad */
6643       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6644       orntNew[0] = ornt[0];
6645       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6646       orntNew[1] = ornt[1];
6647       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6648       orntNew[2] = 0;
6649       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6650       orntNew[3] = 0;
6651       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6652       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6653 #if 1
6654       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6655       for (p = 0; p < 4; ++p) {
6656         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6657       }
6658 #endif
6659     }
6660     /* Interior split faces have 2 vertices and the same cells as the parent */
6661     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6662     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6663     for (f = fStart; f < fMax; ++f) {
6664       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6665 
6666       for (r = 0; r < 2; ++r) {
6667         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6668         const PetscInt *cone, *support;
6669         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6670 
6671         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6672         coneNew[0]       = vStartNew + (cone[0] - vStart);
6673         coneNew[1]       = vStartNew + (cone[1] - vStart);
6674         coneNew[(r+1)%2] = newv;
6675         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6676 #if 1
6677         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6678         for (p = 0; p < 2; ++p) {
6679           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6680         }
6681 #endif
6682         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6683         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6684         for (s = 0; s < supportSize; ++s) {
6685           if (support[s] >= cMax) {
6686             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6687           } else {
6688             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6689             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6690             for (c = 0; c < coneSize; ++c) {
6691               if (cone[c] == f) break;
6692             }
6693             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6694           }
6695         }
6696         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6697 #if 1
6698         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6699         for (p = 0; p < supportSize; ++p) {
6700           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6701         }
6702 #endif
6703       }
6704     }
6705     /* Interior cell faces have 2 vertices and 2 cells */
6706     for (c = cStart; c < cMax; ++c) {
6707       const PetscInt *cone;
6708 
6709       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6710       for (r = 0; r < 3; ++r) {
6711         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6712         PetscInt       coneNew[2];
6713         PetscInt       supportNew[2];
6714 
6715         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6716         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6717         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6718 #if 1
6719         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6720         for (p = 0; p < 2; ++p) {
6721           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6722         }
6723 #endif
6724         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6725         supportNew[1] = (c - cStart)*4 + 3;
6726         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6727 #if 1
6728         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6729         for (p = 0; p < 2; ++p) {
6730           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6731         }
6732 #endif
6733       }
6734     }
6735     /* Interior hybrid faces have 2 vertices and the same cells */
6736     for (f = fMax; f < fEnd; ++f) {
6737       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6738       const PetscInt *cone;
6739       const PetscInt *support;
6740       PetscInt        coneNew[2];
6741       PetscInt        supportNew[2];
6742       PetscInt        size, s, r;
6743 
6744       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6745       coneNew[0] = vStartNew + (cone[0] - vStart);
6746       coneNew[1] = vStartNew + (cone[1] - vStart);
6747       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6748 #if 1
6749       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6750       for (p = 0; p < 2; ++p) {
6751         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6752       }
6753 #endif
6754       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6755       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6756       for (s = 0; s < size; ++s) {
6757         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6758         for (r = 0; r < 2; ++r) {
6759           if (cone[r+2] == f) break;
6760         }
6761         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6762       }
6763       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6764 #if 1
6765       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6766       for (p = 0; p < size; ++p) {
6767         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6768       }
6769 #endif
6770     }
6771     /* Cell hybrid faces have 2 vertices and 2 cells */
6772     for (c = cMax; c < cEnd; ++c) {
6773       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6774       const PetscInt *cone;
6775       PetscInt        coneNew[2];
6776       PetscInt        supportNew[2];
6777 
6778       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6779       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6780       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6781       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6782 #if 1
6783       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6784       for (p = 0; p < 2; ++p) {
6785         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6786       }
6787 #endif
6788       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6789       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6790       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6791 #if 1
6792       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6793       for (p = 0; p < 2; ++p) {
6794         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6795       }
6796 #endif
6797     }
6798     /* Old vertices have identical supports */
6799     for (v = vStart; v < vEnd; ++v) {
6800       const PetscInt  newp = vStartNew + (v - vStart);
6801       const PetscInt *support, *cone;
6802       PetscInt        size, s;
6803 
6804       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6805       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6806       for (s = 0; s < size; ++s) {
6807         if (support[s] >= fMax) {
6808           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6809         } else {
6810           PetscInt r = 0;
6811 
6812           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6813           if (cone[1] == v) r = 1;
6814           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6815         }
6816       }
6817       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6818 #if 1
6819       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6820       for (p = 0; p < size; ++p) {
6821         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6822       }
6823 #endif
6824     }
6825     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6826     for (f = fStart; f < fMax; ++f) {
6827       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6828       const PetscInt *cone, *support;
6829       PetscInt        size, newSize = 2, s;
6830 
6831       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6832       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6833       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6834       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6835       for (s = 0; s < size; ++s) {
6836         PetscInt r = 0;
6837 
6838         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6839         if (support[s] >= cMax) {
6840           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6841 
6842           newSize += 1;
6843         } else {
6844           if      (cone[1] == f) r = 1;
6845           else if (cone[2] == f) r = 2;
6846           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6847           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6848 
6849           newSize += 2;
6850         }
6851       }
6852       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6853 #if 1
6854       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6855       for (p = 0; p < newSize; ++p) {
6856         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6857       }
6858 #endif
6859     }
6860     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6861     break;
6862   default:
6863     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6864   }
6865   PetscFunctionReturn(0);
6866 }
6867 
6868 #undef __FUNCT__
6869 #define __FUNCT__ "CellRefinerSetCoordinates"
6870 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6871 {
6872   PetscSection   coordSection, coordSectionNew;
6873   Vec            coordinates, coordinatesNew;
6874   PetscScalar   *coords, *coordsNew;
6875   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6876   PetscErrorCode ierr;
6877 
6878   PetscFunctionBegin;
6879   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6880   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6881   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6882   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6883   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6884   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6885   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6886   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6887   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6888   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6889   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6890   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6891   if (fMax < 0) fMax = fEnd;
6892   switch (refiner) {
6893   case 1:
6894   case 2:
6895   case 3:
6896     /* Simplicial and Hex 2D */
6897     /* All vertices have the dim coordinates */
6898     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6899       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6900       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6901     }
6902     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6903     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6904     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6905     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6906     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6907     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6908     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6909     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6910     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6911     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6912     /* Old vertices have the same coordinates */
6913     for (v = vStart; v < vEnd; ++v) {
6914       const PetscInt newv = vStartNew + (v - vStart);
6915       PetscInt       off, offnew, d;
6916 
6917       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6918       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6919       for (d = 0; d < dim; ++d) {
6920         coordsNew[offnew+d] = coords[off+d];
6921       }
6922     }
6923     /* Face vertices have the average of endpoint coordinates */
6924     for (f = fStart; f < fMax; ++f) {
6925       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6926       const PetscInt *cone;
6927       PetscInt        coneSize, offA, offB, offnew, d;
6928 
6929       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6930       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6931       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6932       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6933       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6934       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6935       for (d = 0; d < dim; ++d) {
6936         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6937       }
6938     }
6939     /* Just Hex 2D */
6940     if (refiner == 2) {
6941       /* Cell vertices have the average of corner coordinates */
6942       for (c = cStart; c < cEnd; ++c) {
6943         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6944         PetscInt      *cone = PETSC_NULL;
6945         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6946 
6947         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6948         for (p = 0; p < closureSize*2; p += 2) {
6949           const PetscInt point = cone[p];
6950           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6951         }
6952         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6953         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6954         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6955         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6956         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6957         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6958         for (d = 0; d < dim; ++d) {
6959           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6960         }
6961         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6962       }
6963     }
6964     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6965     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6966     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6967     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6968     break;
6969   default:
6970     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6971   }
6972   PetscFunctionReturn(0);
6973 }
6974 
6975 #undef __FUNCT__
6976 #define __FUNCT__ "DMPlexCreateProcessSF"
6977 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6978 {
6979   PetscInt           numRoots, numLeaves, l;
6980   const PetscInt    *localPoints;
6981   const PetscSFNode *remotePoints;
6982   PetscInt          *localPointsNew;
6983   PetscSFNode       *remotePointsNew;
6984   PetscInt          *ranks, *ranksNew;
6985   PetscErrorCode     ierr;
6986 
6987   PetscFunctionBegin;
6988   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6989   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6990   for (l = 0; l < numLeaves; ++l) {
6991     ranks[l] = remotePoints[l].rank;
6992   }
6993   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6994   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6995   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6996   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6997   for (l = 0; l < numLeaves; ++l) {
6998     ranksNew[l]              = ranks[l];
6999     localPointsNew[l]        = l;
7000     remotePointsNew[l].index = 0;
7001     remotePointsNew[l].rank  = ranksNew[l];
7002   }
7003   ierr = PetscFree(ranks);CHKERRQ(ierr);
7004   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
7005   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
7006   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7007   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7008   PetscFunctionReturn(0);
7009 }
7010 
7011 #undef __FUNCT__
7012 #define __FUNCT__ "CellRefinerCreateSF"
7013 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7014 {
7015   PetscSF            sf, sfNew, sfProcess;
7016   IS                 processRanks;
7017   MPI_Datatype       depthType;
7018   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7019   const PetscInt    *localPoints, *neighbors;
7020   const PetscSFNode *remotePoints;
7021   PetscInt          *localPointsNew;
7022   PetscSFNode       *remotePointsNew;
7023   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7024   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7025   PetscErrorCode     ierr;
7026 
7027   PetscFunctionBegin;
7028   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7029   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7030   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7031   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7032   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7033   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7034   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7035   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7036   switch (refiner) {
7037   case 3:
7038     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7039     cMax = PetscMin(cEnd, cMax);
7040     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7041     fMax = PetscMin(fEnd, fMax);
7042   }
7043   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7044   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7045   /* Caculate size of new SF */
7046   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7047   if (numRoots < 0) PetscFunctionReturn(0);
7048   for (l = 0; l < numLeaves; ++l) {
7049     const PetscInt p = localPoints[l];
7050 
7051     switch (refiner) {
7052     case 1:
7053       /* Simplicial 2D */
7054       if ((p >= vStart) && (p < vEnd)) {
7055         /* Old vertices stay the same */
7056         ++numLeavesNew;
7057       } else if ((p >= fStart) && (p < fEnd)) {
7058         /* Old faces add new faces and vertex */
7059         numLeavesNew += 1 + 2;
7060       } else if ((p >= cStart) && (p < cEnd)) {
7061         /* Old cells add new cells and interior faces */
7062         numLeavesNew += 4 + 3;
7063       }
7064       break;
7065     case 2:
7066       /* Hex 2D */
7067       if ((p >= vStart) && (p < vEnd)) {
7068         /* Old vertices stay the same */
7069         ++numLeavesNew;
7070       } else if ((p >= fStart) && (p < fEnd)) {
7071         /* Old faces add new faces and vertex */
7072         numLeavesNew += 1 + 2;
7073       } else if ((p >= cStart) && (p < cEnd)) {
7074         /* Old cells add new cells and interior faces */
7075         numLeavesNew += 4 + 4;
7076       }
7077       break;
7078     default:
7079       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7080     }
7081   }
7082   /* Communicate depthSizes for each remote rank */
7083   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7084   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7085   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7086   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);
7087   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7088   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7089   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7090   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7091   for (n = 0; n < numNeighbors; ++n) {
7092     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7093   }
7094   depthSizeOld[depth]   = cMax;
7095   depthSizeOld[0]       = vMax;
7096   depthSizeOld[depth-1] = fMax;
7097   depthSizeOld[1]       = eMax;
7098 
7099   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7100   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7101 
7102   depthSizeOld[depth]   = cEnd - cStart;
7103   depthSizeOld[0]       = vEnd - vStart;
7104   depthSizeOld[depth-1] = fEnd - fStart;
7105   depthSizeOld[1]       = eEnd - eStart;
7106 
7107   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7108   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7109   for (n = 0; n < numNeighbors; ++n) {
7110     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7111   }
7112   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7113   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7114   /* Calculate new point SF */
7115   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7116   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7117   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7118   for (l = 0, m = 0; l < numLeaves; ++l) {
7119     PetscInt    p     = localPoints[l];
7120     PetscInt    rp    = remotePoints[l].index, n;
7121     PetscMPIInt rrank = remotePoints[l].rank;
7122 
7123     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7124     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7125     switch (refiner) {
7126     case 1:
7127       /* Simplicial 2D */
7128       if ((p >= vStart) && (p < vEnd)) {
7129         /* Old vertices stay the same */
7130         localPointsNew[m]        = vStartNew     + (p  - vStart);
7131         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7132         remotePointsNew[m].rank  = rrank;
7133         ++m;
7134       } else if ((p >= fStart) && (p < fEnd)) {
7135         /* Old faces add new faces and vertex */
7136         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7137         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7138         remotePointsNew[m].rank  = rrank;
7139         ++m;
7140         for (r = 0; r < 2; ++r, ++m) {
7141           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7142           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7143           remotePointsNew[m].rank  = rrank;
7144         }
7145       } else if ((p >= cStart) && (p < cEnd)) {
7146         /* Old cells add new cells and interior faces */
7147         for (r = 0; r < 4; ++r, ++m) {
7148           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7149           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7150           remotePointsNew[m].rank  = rrank;
7151         }
7152         for (r = 0; r < 3; ++r, ++m) {
7153           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7154           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7155           remotePointsNew[m].rank  = rrank;
7156         }
7157       }
7158       break;
7159     case 2:
7160       /* Hex 2D */
7161       if ((p >= vStart) && (p < vEnd)) {
7162         /* Old vertices stay the same */
7163         localPointsNew[m]        = vStartNew     + (p  - vStart);
7164         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7165         remotePointsNew[m].rank  = rrank;
7166         ++m;
7167       } else if ((p >= fStart) && (p < fEnd)) {
7168         /* Old faces add new faces and vertex */
7169         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7170         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7171         remotePointsNew[m].rank  = rrank;
7172         ++m;
7173         for (r = 0; r < 2; ++r, ++m) {
7174           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7175           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7176           remotePointsNew[m].rank  = rrank;
7177         }
7178       } else if ((p >= cStart) && (p < cEnd)) {
7179         /* Old cells add new cells and interior faces */
7180         for (r = 0; r < 4; ++r, ++m) {
7181           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7182           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7183           remotePointsNew[m].rank  = rrank;
7184         }
7185         for (r = 0; r < 4; ++r, ++m) {
7186           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7187           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7188           remotePointsNew[m].rank  = rrank;
7189         }
7190       }
7191       break;
7192     case 3:
7193       /* Hybrid simplicial 2D */
7194       if ((p >= vStart) && (p < vEnd)) {
7195         /* Old vertices stay the same */
7196         localPointsNew[m]        = vStartNew     + (p  - vStart);
7197         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7198         remotePointsNew[m].rank  = rrank;
7199         ++m;
7200       } else if ((p >= fStart) && (p < fMax)) {
7201         /* Old interior faces add new faces and vertex */
7202         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7203         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7204         remotePointsNew[m].rank  = rrank;
7205         ++m;
7206         for (r = 0; r < 2; ++r, ++m) {
7207           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7208           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7209           remotePointsNew[m].rank  = rrank;
7210         }
7211       } else if ((p >= fMax) && (p < fEnd)) {
7212         /* Old hybrid faces stay the same */
7213         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7214         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7215         remotePointsNew[m].rank  = rrank;
7216         ++m;
7217       } else if ((p >= cStart) && (p < cMax)) {
7218         /* Old interior cells add new cells and interior faces */
7219         for (r = 0; r < 4; ++r, ++m) {
7220           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7221           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7222           remotePointsNew[m].rank  = rrank;
7223         }
7224         for (r = 0; r < 3; ++r, ++m) {
7225           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7226           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7227           remotePointsNew[m].rank  = rrank;
7228         }
7229       } else if ((p >= cStart) && (p < cMax)) {
7230         /* Old hybrid cells add new cells and hybrid face */
7231         for (r = 0; r < 2; ++r, ++m) {
7232           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7233           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7234           remotePointsNew[m].rank  = rrank;
7235         }
7236         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7237         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]);
7238         remotePointsNew[m].rank  = rrank;
7239         ++m;
7240       }
7241       break;
7242     default:
7243       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7244     }
7245   }
7246   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7247   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7248   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7249   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7250   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7251   PetscFunctionReturn(0);
7252 }
7253 
7254 #undef __FUNCT__
7255 #define __FUNCT__ "CellRefinerCreateLabels"
7256 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7257 {
7258   PetscInt       numLabels, l;
7259   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7260   PetscErrorCode ierr;
7261 
7262   PetscFunctionBegin;
7263   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7264   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7265   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7266   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7267 
7268   cStartNew = 0;
7269   vStartNew = depthSize[2];
7270   fStartNew = depthSize[2] + depthSize[0];
7271 
7272   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7273   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7274   switch (refiner) {
7275   case 3:
7276     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7277     cMax = PetscMin(cEnd, cMax);
7278     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7279     fMax = PetscMin(fEnd, fMax);
7280   }
7281   for (l = 0; l < numLabels; ++l) {
7282     DMLabel         label, labelNew;
7283     const char     *lname;
7284     PetscBool       isDepth;
7285     IS              valueIS;
7286     const PetscInt *values;
7287     PetscInt        numValues, val;
7288 
7289     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7290     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7291     if (isDepth) continue;
7292     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7293     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7294     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7295     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7296     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7297     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7298     for (val = 0; val < numValues; ++val) {
7299       IS              pointIS;
7300       const PetscInt *points;
7301       PetscInt        numPoints, n;
7302 
7303       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7304       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7305       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7306       for (n = 0; n < numPoints; ++n) {
7307         const PetscInt p = points[n];
7308         switch (refiner) {
7309         case 1:
7310           /* Simplicial 2D */
7311           if ((p >= vStart) && (p < vEnd)) {
7312             /* Old vertices stay the same */
7313             newp = vStartNew + (p - vStart);
7314             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7315           } else if ((p >= fStart) && (p < fEnd)) {
7316             /* Old faces add new faces and vertex */
7317             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7318             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7319             for (r = 0; r < 2; ++r) {
7320               newp = fStartNew + (p - fStart)*2 + r;
7321               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7322             }
7323           } else if ((p >= cStart) && (p < cEnd)) {
7324             /* Old cells add new cells and interior faces */
7325             for (r = 0; r < 4; ++r) {
7326               newp = cStartNew + (p - cStart)*4 + r;
7327               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7328             }
7329             for (r = 0; r < 3; ++r) {
7330               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7331               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7332             }
7333           }
7334           break;
7335         case 2:
7336           /* Hex 2D */
7337           if ((p >= vStart) && (p < vEnd)) {
7338             /* Old vertices stay the same */
7339             newp = vStartNew + (p - vStart);
7340             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7341           } else if ((p >= fStart) && (p < fEnd)) {
7342             /* Old faces add new faces and vertex */
7343             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7344             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7345             for (r = 0; r < 2; ++r) {
7346               newp = fStartNew + (p - fStart)*2 + r;
7347               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7348             }
7349           } else if ((p >= cStart) && (p < cEnd)) {
7350             /* Old cells add new cells and interior faces and vertex */
7351             for (r = 0; r < 4; ++r) {
7352               newp = cStartNew + (p - cStart)*4 + r;
7353               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7354             }
7355             for (r = 0; r < 4; ++r) {
7356               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7357               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7358             }
7359             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7360             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7361           }
7362           break;
7363         case 3:
7364           /* Hybrid simplicial 2D */
7365           if ((p >= vStart) && (p < vEnd)) {
7366             /* Old vertices stay the same */
7367             newp = vStartNew + (p - vStart);
7368             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7369           } else if ((p >= fStart) && (p < fMax)) {
7370             /* Old interior faces add new faces and vertex */
7371             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7372             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7373             for (r = 0; r < 2; ++r) {
7374               newp = fStartNew + (p - fStart)*2 + r;
7375               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7376             }
7377           } else if ((p >= fMax) && (p < fEnd)) {
7378             /* Old hybrid faces stay the same */
7379             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7380             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7381           } else if ((p >= cStart) && (p < cMax)) {
7382             /* Old interior cells add new cells and interior faces */
7383             for (r = 0; r < 4; ++r) {
7384               newp = cStartNew + (p - cStart)*4 + r;
7385               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7386             }
7387             for (r = 0; r < 3; ++r) {
7388               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7389               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7390             }
7391           } else if ((p >= cMax) && (p < cEnd)) {
7392             /* Old hybrid cells add new cells and hybrid face */
7393             for (r = 0; r < 2; ++r) {
7394               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7395               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7396             }
7397             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7398             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7399           }
7400           break;
7401         default:
7402           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7403         }
7404       }
7405       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7406       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7407     }
7408     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7409     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7410     if (0) {
7411       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7412       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7413       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7414     }
7415   }
7416   PetscFunctionReturn(0);
7417 }
7418 
7419 #undef __FUNCT__
7420 #define __FUNCT__ "DMPlexRefine_Uniform"
7421 /* This will only work for interpolated meshes */
7422 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7423 {
7424   DM             rdm;
7425   PetscInt      *depthSize;
7426   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7427   PetscErrorCode ierr;
7428 
7429   PetscFunctionBegin;
7430   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7431   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7432   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7433   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7434   /* Calculate number of new points of each depth */
7435   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7436   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7437   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7438   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7439   /* Step 1: Set chart */
7440   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7441   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7442   /* Step 2: Set cone/support sizes */
7443   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7444   /* Step 3: Setup refined DM */
7445   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7446   /* Step 4: Set cones and supports */
7447   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7448   /* Step 5: Stratify */
7449   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7450   /* Step 6: Set coordinates for vertices */
7451   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7452   /* Step 7: Create pointSF */
7453   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7454   /* Step 8: Create labels */
7455   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7456   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7457 
7458   *dmRefined = rdm;
7459   PetscFunctionReturn(0);
7460 }
7461 
7462 #undef __FUNCT__
7463 #define __FUNCT__ "DMPlexSetRefinementUniform"
7464 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7465 {
7466   DM_Plex *mesh = (DM_Plex*) dm->data;
7467 
7468   PetscFunctionBegin;
7469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7470   mesh->refinementUniform = refinementUniform;
7471   PetscFunctionReturn(0);
7472 }
7473 
7474 #undef __FUNCT__
7475 #define __FUNCT__ "DMPlexGetRefinementUniform"
7476 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7477 {
7478   DM_Plex *mesh = (DM_Plex*) dm->data;
7479 
7480   PetscFunctionBegin;
7481   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7482   PetscValidPointer(refinementUniform,  2);
7483   *refinementUniform = mesh->refinementUniform;
7484   PetscFunctionReturn(0);
7485 }
7486 
7487 #undef __FUNCT__
7488 #define __FUNCT__ "DMPlexSetRefinementLimit"
7489 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7490 {
7491   DM_Plex *mesh = (DM_Plex*) dm->data;
7492 
7493   PetscFunctionBegin;
7494   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7495   mesh->refinementLimit = refinementLimit;
7496   PetscFunctionReturn(0);
7497 }
7498 
7499 #undef __FUNCT__
7500 #define __FUNCT__ "DMPlexGetRefinementLimit"
7501 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7502 {
7503   DM_Plex *mesh = (DM_Plex*) dm->data;
7504 
7505   PetscFunctionBegin;
7506   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7507   PetscValidPointer(refinementLimit,  2);
7508   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7509   *refinementLimit = mesh->refinementLimit;
7510   PetscFunctionReturn(0);
7511 }
7512 
7513 #undef __FUNCT__
7514 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7515 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7516 {
7517   PetscInt       dim, cStart, coneSize, cMax;
7518   PetscErrorCode ierr;
7519 
7520   PetscFunctionBegin;
7521   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7522   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7523   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7524   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7525   switch (dim) {
7526   case 2:
7527     switch (coneSize) {
7528     case 3:
7529       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7530       else *cellRefiner = 1; /* Triangular */
7531       break;
7532     case 4:
7533       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7534       else *cellRefiner = 2; /* Quadrilateral */
7535       break;
7536     default:
7537       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7538     }
7539     break;
7540   default:
7541     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7542   }
7543   PetscFunctionReturn(0);
7544 }
7545 
7546 #undef __FUNCT__
7547 #define __FUNCT__ "DMRefine_Plex"
7548 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7549 {
7550   PetscReal      refinementLimit;
7551   PetscInt       dim, cStart, cEnd;
7552   char           genname[1024], *name = PETSC_NULL;
7553   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7554   PetscErrorCode ierr;
7555 
7556   PetscFunctionBegin;
7557   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7558   if (isUniform) {
7559     CellRefiner cellRefiner;
7560 
7561     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7562     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7563     PetscFunctionReturn(0);
7564   }
7565   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7566   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7567   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7568   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7569   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7570   if (flg) name = genname;
7571   if (name) {
7572     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7573     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7574     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7575   }
7576   switch (dim) {
7577   case 2:
7578     if (!name || isTriangle) {
7579 #if defined(PETSC_HAVE_TRIANGLE)
7580       double  *maxVolumes;
7581       PetscInt c;
7582 
7583       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7584       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7585       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7586 #else
7587       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7588 #endif
7589     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7590     break;
7591   case 3:
7592     if (!name || isCTetgen) {
7593 #if defined(PETSC_HAVE_CTETGEN)
7594       PetscReal *maxVolumes;
7595       PetscInt   c;
7596 
7597       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7598       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7599       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7600 #else
7601       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7602 #endif
7603     } else if (isTetgen) {
7604 #if defined(PETSC_HAVE_TETGEN)
7605       double  *maxVolumes;
7606       PetscInt c;
7607 
7608       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7609       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7610       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7611 #else
7612       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7613 #endif
7614     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7615     break;
7616   default:
7617     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7618   }
7619   PetscFunctionReturn(0);
7620 }
7621 
7622 #undef __FUNCT__
7623 #define __FUNCT__ "DMPlexGetDepth"
7624 /*@
7625   DMPlexGetDepth - get the number of strata
7626 
7627   Not Collective
7628 
7629   Input Parameters:
7630 . dm           - The DMPlex object
7631 
7632   Output Parameters:
7633 . depth - number of strata
7634 
7635   Level: developer
7636 
7637   Notes:
7638   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7639 
7640 .keywords: mesh, points
7641 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7642 @*/
7643 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7644 {
7645   PetscInt       d;
7646   PetscErrorCode ierr;
7647 
7648   PetscFunctionBegin;
7649   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7650   PetscValidPointer(depth, 2);
7651   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7652   *depth = d-1;
7653   PetscFunctionReturn(0);
7654 }
7655 
7656 #undef __FUNCT__
7657 #define __FUNCT__ "DMPlexGetDepthStratum"
7658 /*@
7659   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7660 
7661   Not Collective
7662 
7663   Input Parameters:
7664 + dm           - The DMPlex object
7665 - stratumValue - The requested depth
7666 
7667   Output Parameters:
7668 + start - The first point at this depth
7669 - end   - One beyond the last point at this depth
7670 
7671   Level: developer
7672 
7673 .keywords: mesh, points
7674 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7675 @*/
7676 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7677 {
7678   DM_Plex       *mesh = (DM_Plex*) dm->data;
7679   DMLabel        next  = mesh->labels;
7680   PetscBool      flg   = PETSC_FALSE;
7681   PetscInt       depth;
7682   PetscErrorCode ierr;
7683 
7684   PetscFunctionBegin;
7685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7686   if (stratumValue < 0) {
7687     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7688     PetscFunctionReturn(0);
7689   } else {
7690     PetscInt pStart, pEnd;
7691 
7692     if (start) *start = 0;
7693     if (end)   *end   = 0;
7694     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7695     if (pStart == pEnd) PetscFunctionReturn(0);
7696   }
7697   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7698   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7699   /* We should have a generic GetLabel() and a Label class */
7700   while (next) {
7701     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7702     if (flg) break;
7703     next = next->next;
7704   }
7705   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7706   depth = stratumValue;
7707   if ((depth < 0) || (depth >= next->numStrata)) {
7708     if (start) *start = 0;
7709     if (end)   *end   = 0;
7710   } else {
7711     if (start) *start = next->points[next->stratumOffsets[depth]];
7712     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7713   }
7714   PetscFunctionReturn(0);
7715 }
7716 
7717 #undef __FUNCT__
7718 #define __FUNCT__ "DMPlexGetHeightStratum"
7719 /*@
7720   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7721 
7722   Not Collective
7723 
7724   Input Parameters:
7725 + dm           - The DMPlex object
7726 - stratumValue - The requested height
7727 
7728   Output Parameters:
7729 + start - The first point at this height
7730 - end   - One beyond the last point at this height
7731 
7732   Level: developer
7733 
7734 .keywords: mesh, points
7735 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7736 @*/
7737 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7738 {
7739   DM_Plex       *mesh = (DM_Plex*) dm->data;
7740   DMLabel        next  = mesh->labels;
7741   PetscBool      flg   = PETSC_FALSE;
7742   PetscInt       depth;
7743   PetscErrorCode ierr;
7744 
7745   PetscFunctionBegin;
7746   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7747   if (stratumValue < 0) {
7748     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7749   } else {
7750     PetscInt pStart, pEnd;
7751 
7752     if (start) *start = 0;
7753     if (end)   *end   = 0;
7754     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7755     if (pStart == pEnd) PetscFunctionReturn(0);
7756   }
7757   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7758   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7759   /* We should have a generic GetLabel() and a Label class */
7760   while (next) {
7761     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7762     if (flg) break;
7763     next = next->next;
7764   }
7765   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7766   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7767   if ((depth < 0) || (depth >= next->numStrata)) {
7768     if (start) *start = 0;
7769     if (end)   *end   = 0;
7770   } else {
7771     if (start) *start = next->points[next->stratumOffsets[depth]];
7772     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7773   }
7774   PetscFunctionReturn(0);
7775 }
7776 
7777 #undef __FUNCT__
7778 #define __FUNCT__ "DMPlexCreateSectionInitial"
7779 /* Set the number of dof on each point and separate by fields */
7780 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7781 {
7782   PetscInt      *numDofTot;
7783   PetscInt       pStart = 0, pEnd = 0;
7784   PetscInt       p, d, f;
7785   PetscErrorCode ierr;
7786 
7787   PetscFunctionBegin;
7788   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7789   for (d = 0; d <= dim; ++d) {
7790     numDofTot[d] = 0;
7791     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
7792   }
7793   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7794   if (numFields > 0) {
7795     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7796     if (numComp) {
7797       for (f = 0; f < numFields; ++f) {
7798         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7799       }
7800     }
7801   }
7802   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7803   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7804   for (d = 0; d <= dim; ++d) {
7805     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7806     for (p = pStart; p < pEnd; ++p) {
7807       for (f = 0; f < numFields; ++f) {
7808         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7809       }
7810       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7811     }
7812   }
7813   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7814   PetscFunctionReturn(0);
7815 }
7816 
7817 #undef __FUNCT__
7818 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7819 /* Set the number of dof on each point and separate by fields
7820    If constDof is PETSC_DETERMINE, constrain every dof on the point
7821 */
7822 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7823 {
7824   PetscInt       numFields;
7825   PetscInt       bc;
7826   PetscErrorCode ierr;
7827 
7828   PetscFunctionBegin;
7829   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7830   for (bc = 0; bc < numBC; ++bc) {
7831     PetscInt        field = 0;
7832     const PetscInt *idx;
7833     PetscInt        n, i;
7834 
7835     if (numFields) field = bcField[bc];
7836     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
7837     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7838     for (i = 0; i < n; ++i) {
7839       const PetscInt p        = idx[i];
7840       PetscInt       numConst = constDof;
7841 
7842       /* Constrain every dof on the point */
7843       if (numConst < 0) {
7844         if (numFields) {
7845           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
7846         } else {
7847           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
7848         }
7849       }
7850       if (numFields) {
7851         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
7852       }
7853       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
7854     }
7855     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
7856   }
7857   PetscFunctionReturn(0);
7858 }
7859 
7860 #undef __FUNCT__
7861 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
7862 /* Set the constrained indices on each point and separate by fields */
7863 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
7864 {
7865   PetscInt      *maxConstraints;
7866   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
7867   PetscErrorCode ierr;
7868 
7869   PetscFunctionBegin;
7870   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7871   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7872   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
7873   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
7874   for (p = pStart; p < pEnd; ++p) {
7875     PetscInt cdof;
7876 
7877     if (numFields) {
7878       for (f = 0; f < numFields; ++f) {
7879         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
7880         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
7881       }
7882     } else {
7883       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7884       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
7885     }
7886   }
7887   for (f = 0; f < numFields; ++f) {
7888     maxConstraints[numFields] += maxConstraints[f];
7889   }
7890   if (maxConstraints[numFields]) {
7891     PetscInt *indices;
7892 
7893     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7894     for (p = pStart; p < pEnd; ++p) {
7895       PetscInt cdof, d;
7896 
7897       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7898       if (cdof) {
7899         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7900         if (numFields) {
7901           PetscInt numConst = 0, foff = 0;
7902 
7903           for (f = 0; f < numFields; ++f) {
7904             PetscInt cfdof, fdof;
7905 
7906             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7907             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7908             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7909             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
7910             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7911             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
7912             numConst += cfdof;
7913             foff     += fdof;
7914           }
7915           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7916         } else {
7917           for (d = 0; d < cdof; ++d) indices[d] = d;
7918         }
7919         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7920       }
7921     }
7922     ierr = PetscFree(indices);CHKERRQ(ierr);
7923   }
7924   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7925   PetscFunctionReturn(0);
7926 }
7927 
7928 #undef __FUNCT__
7929 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7930 /* Set the constrained field indices on each point */
7931 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
7932 {
7933   const PetscInt *points, *indices;
7934   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7935   PetscErrorCode  ierr;
7936 
7937   PetscFunctionBegin;
7938   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7939   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7940 
7941   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7942   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7943   if (!constraintIndices) {
7944     PetscInt *idx, i;
7945 
7946     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7947     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7948     for (i = 0; i < maxDof; ++i) idx[i] = i;
7949     for (p = 0; p < numPoints; ++p) {
7950       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7951     }
7952     ierr = PetscFree(idx);CHKERRQ(ierr);
7953   } else {
7954     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7955     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7956     for (p = 0; p < numPoints; ++p) {
7957       PetscInt fcdof;
7958 
7959       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7960       if (fcdof != numConstraints) SETERRQ4(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
7961       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7962     }
7963     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7964   }
7965   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7966   PetscFunctionReturn(0);
7967 }
7968 
7969 #undef __FUNCT__
7970 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7971 /* Set the constrained indices on each point and separate by fields */
7972 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
7973 {
7974   PetscInt      *indices;
7975   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7976   PetscErrorCode ierr;
7977 
7978   PetscFunctionBegin;
7979   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7980   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7981   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7982   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7983   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7984   for (p = pStart; p < pEnd; ++p) {
7985     PetscInt cdof, d;
7986 
7987     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7988     if (cdof) {
7989       PetscInt numConst = 0, foff = 0;
7990 
7991       for (f = 0; f < numFields; ++f) {
7992         const PetscInt *fcind;
7993         PetscInt        fdof, fcdof;
7994 
7995         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7996         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7997         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7998         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7999         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
8000         foff     += fdof;
8001         numConst += fcdof;
8002       }
8003       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8004       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8005     }
8006   }
8007   ierr = PetscFree(indices);CHKERRQ(ierr);
8008   PetscFunctionReturn(0);
8009 }
8010 
8011 #undef __FUNCT__
8012 #define __FUNCT__ "DMPlexCreateSection"
8013 /*@C
8014   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8015 
8016   Not Collective
8017 
8018   Input Parameters:
8019 + dm        - The DMPlex object
8020 . dim       - The spatial dimension of the problem
8021 . numFields - The number of fields in the problem
8022 . numComp   - An array of size numFields that holds the number of components for each field
8023 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8024 . numBC     - The number of boundary conditions
8025 . bcField   - An array of size numBC giving the field number for each boundry condition
8026 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8027 
8028   Output Parameter:
8029 . section - The PetscSection object
8030 
8031   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
8032   nubmer of dof for field 0 on each edge.
8033 
8034   Level: developer
8035 
8036 .keywords: mesh, elements
8037 .seealso: DMPlexCreate(), PetscSectionCreate()
8038 @*/
8039 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8040 {
8041   PetscErrorCode ierr;
8042 
8043   PetscFunctionBegin;
8044   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8045   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8046   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8047   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8048   {
8049     PetscBool view = PETSC_FALSE;
8050 
8051     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8052     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8053   }
8054   PetscFunctionReturn(0);
8055 }
8056 
8057 #undef __FUNCT__
8058 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8059 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8060 {
8061   PetscSection   section;
8062   PetscErrorCode ierr;
8063 
8064   PetscFunctionBegin;
8065   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8066   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8067   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8068   PetscFunctionReturn(0);
8069 }
8070 
8071 #undef __FUNCT__
8072 #define __FUNCT__ "DMPlexGetCoordinateSection"
8073 /*@
8074   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8075 
8076   Not Collective
8077 
8078   Input Parameter:
8079 . dm - The DMPlex object
8080 
8081   Output Parameter:
8082 . section - The PetscSection object
8083 
8084   Level: intermediate
8085 
8086 .keywords: mesh, coordinates
8087 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8088 @*/
8089 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8090 {
8091   DM             cdm;
8092   PetscErrorCode ierr;
8093 
8094   PetscFunctionBegin;
8095   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8096   PetscValidPointer(section, 2);
8097   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8098   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8099   PetscFunctionReturn(0);
8100 }
8101 
8102 #undef __FUNCT__
8103 #define __FUNCT__ "DMPlexSetCoordinateSection"
8104 /*@
8105   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8106 
8107   Not Collective
8108 
8109   Input Parameters:
8110 + dm      - The DMPlex object
8111 - section - The PetscSection object
8112 
8113   Level: intermediate
8114 
8115 .keywords: mesh, coordinates
8116 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8117 @*/
8118 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8119 {
8120   DM             cdm;
8121   PetscErrorCode ierr;
8122 
8123   PetscFunctionBegin;
8124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8125   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8126   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8127   PetscFunctionReturn(0);
8128 }
8129 
8130 #undef __FUNCT__
8131 #define __FUNCT__ "DMPlexGetConeSection"
8132 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8133 {
8134   DM_Plex *mesh = (DM_Plex*) dm->data;
8135 
8136   PetscFunctionBegin;
8137   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8138   if (section) *section = mesh->coneSection;
8139   PetscFunctionReturn(0);
8140 }
8141 
8142 #undef __FUNCT__
8143 #define __FUNCT__ "DMPlexGetCones"
8144 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8145 {
8146   DM_Plex *mesh = (DM_Plex*) dm->data;
8147 
8148   PetscFunctionBegin;
8149   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8150   if (cones) *cones = mesh->cones;
8151   PetscFunctionReturn(0);
8152 }
8153 
8154 #undef __FUNCT__
8155 #define __FUNCT__ "DMPlexGetConeOrientations"
8156 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8157 {
8158   DM_Plex *mesh = (DM_Plex*) dm->data;
8159 
8160   PetscFunctionBegin;
8161   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8162   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8163   PetscFunctionReturn(0);
8164 }
8165 
8166 #undef __FUNCT__
8167 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8168 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8169 {
8170   const PetscInt embedDim = 2;
8171   PetscReal      x        = PetscRealPart(point[0]);
8172   PetscReal      y        = PetscRealPart(point[1]);
8173   PetscReal      v0[2], J[4], invJ[4], detJ;
8174   PetscReal      xi, eta;
8175   PetscErrorCode ierr;
8176 
8177   PetscFunctionBegin;
8178   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8179   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8180   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8181 
8182   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8183   else *cell = -1;
8184   PetscFunctionReturn(0);
8185 }
8186 
8187 #undef __FUNCT__
8188 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8189 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8190 {
8191   PetscSection       coordSection;
8192   Vec                coordsLocal;
8193   const PetscScalar *coords;
8194   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8195   PetscReal          x         = PetscRealPart(point[0]);
8196   PetscReal          y         = PetscRealPart(point[1]);
8197   PetscInt           crossings = 0, f;
8198   PetscErrorCode     ierr;
8199 
8200   PetscFunctionBegin;
8201   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8202   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8203   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8204   for (f = 0; f < 4; ++f) {
8205     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8206     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8207     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8208     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8209     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8210     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8211     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8212     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8213     if ((cond1 || cond2)  && above) ++crossings;
8214   }
8215   if (crossings % 2) *cell = c;
8216   else *cell = -1;
8217   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8218   PetscFunctionReturn(0);
8219 }
8220 
8221 #undef __FUNCT__
8222 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8223 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8224 {
8225   const PetscInt embedDim = 3;
8226   PetscReal      v0[3], J[9], invJ[9], detJ;
8227   PetscReal      x = PetscRealPart(point[0]);
8228   PetscReal      y = PetscRealPart(point[1]);
8229   PetscReal      z = PetscRealPart(point[2]);
8230   PetscReal      xi, eta, zeta;
8231   PetscErrorCode ierr;
8232 
8233   PetscFunctionBegin;
8234   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8235   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8236   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8237   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8238 
8239   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8240   else *cell = -1;
8241   PetscFunctionReturn(0);
8242 }
8243 
8244 #undef __FUNCT__
8245 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8246 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8247 {
8248   PetscSection       coordSection;
8249   Vec                coordsLocal;
8250   const PetscScalar *coords;
8251   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8252                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8253   PetscBool          found = PETSC_TRUE;
8254   PetscInt           f;
8255   PetscErrorCode     ierr;
8256 
8257   PetscFunctionBegin;
8258   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8259   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8260   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8261   for (f = 0; f < 6; ++f) {
8262     /* Check the point is under plane */
8263     /*   Get face normal */
8264     PetscReal v_i[3];
8265     PetscReal v_j[3];
8266     PetscReal normal[3];
8267     PetscReal pp[3];
8268     PetscReal dot;
8269 
8270     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8271     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8272     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8273     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8274     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8275     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8276     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8277     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8278     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8279     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8280     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8281     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8282     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8283 
8284     /* Check that projected point is in face (2D location problem) */
8285     if (dot < 0.0) {
8286       found = PETSC_FALSE;
8287       break;
8288     }
8289   }
8290   if (found) *cell = c;
8291   else *cell = -1;
8292   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8293   PetscFunctionReturn(0);
8294 }
8295 
8296 #undef __FUNCT__
8297 #define __FUNCT__ "DMLocatePoints_Plex"
8298 /*
8299  Need to implement using the guess
8300 */
8301 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8302 {
8303   PetscInt       cell = -1 /*, guess = -1*/;
8304   PetscInt       bs, numPoints, p;
8305   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8306   PetscInt      *cells;
8307   PetscScalar   *a;
8308   PetscErrorCode ierr;
8309 
8310   PetscFunctionBegin;
8311   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8312   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8313   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8314   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8315   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8316   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8317   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8318   if (bs != dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
8319   numPoints /= bs;
8320   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8321   for (p = 0; p < numPoints; ++p) {
8322     const PetscScalar *point = &a[p*bs];
8323 
8324     switch (dim) {
8325     case 2:
8326       for (c = cStart; c < cEnd; ++c) {
8327         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8328         switch (coneSize) {
8329         case 3:
8330           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8331           break;
8332         case 4:
8333           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8334           break;
8335         default:
8336           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8337         }
8338         if (cell >= 0) break;
8339       }
8340       break;
8341     case 3:
8342       for (c = cStart; c < cEnd; ++c) {
8343         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8344         switch (coneSize) {
8345         case 4:
8346           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8347           break;
8348         case 8:
8349           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8350           break;
8351         default:
8352           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8353         }
8354         if (cell >= 0) break;
8355       }
8356       break;
8357     default:
8358       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8359     }
8360     cells[p] = cell;
8361   }
8362   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8363   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8364   PetscFunctionReturn(0);
8365 }
8366 
8367 /******************************** FEM Support **********************************/
8368 
8369 #undef __FUNCT__
8370 #define __FUNCT__ "DMPlexVecGetClosure"
8371 /*@C
8372   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8373 
8374   Not collective
8375 
8376   Input Parameters:
8377 + dm - The DM
8378 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8379 . v - The local vector
8380 - point - The sieve point in the DM
8381 
8382   Output Parameters:
8383 + csize - The number of values in the closure, or PETSC_NULL
8384 - values - The array of values, which is a borrowed array and should not be freed
8385 
8386   Level: intermediate
8387 
8388 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8389 @*/
8390 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8391 {
8392   PetscScalar   *array, *vArray;
8393   PetscInt      *points = PETSC_NULL;
8394   PetscInt       offsets[32];
8395   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8396   PetscErrorCode ierr;
8397 
8398   PetscFunctionBegin;
8399   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8400   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8401   if (!section) {
8402     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8403   }
8404   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8405   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8406   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8407   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8408   /* Compress out points not in the section */
8409   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8410   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8411     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8412       points[q*2]   = points[p];
8413       points[q*2+1] = points[p+1];
8414       ++q;
8415     }
8416   }
8417   numPoints = q;
8418   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8419     PetscInt dof, fdof;
8420 
8421     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8422     for (f = 0; f < numFields; ++f) {
8423       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8424       offsets[f+1] += fdof;
8425     }
8426     size += dof;
8427   }
8428   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8429   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8430   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8431   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8432   for (p = 0; p < numPoints*2; p += 2) {
8433     PetscInt     o = points[p+1];
8434     PetscInt     dof, off, d;
8435     PetscScalar *varr;
8436 
8437     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8438     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8439     varr = &vArray[off];
8440     if (numFields) {
8441       PetscInt fdof, foff, fcomp, f, c;
8442 
8443       for (f = 0, foff = 0; f < numFields; ++f) {
8444         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8445         if (o >= 0) {
8446           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8447             array[offsets[f]] = varr[foff+d];
8448           }
8449         } else {
8450           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8451           for (d = fdof/fcomp-1; d >= 0; --d) {
8452             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8453               array[offsets[f]] = varr[foff+d*fcomp+c];
8454             }
8455           }
8456         }
8457         foff += fdof;
8458       }
8459     } else {
8460       if (o >= 0) {
8461         for (d = 0; d < dof; ++d, ++offsets[0]) {
8462           array[offsets[0]] = varr[d];
8463         }
8464       } else {
8465         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8466           array[offsets[0]] = varr[d];
8467         }
8468       }
8469     }
8470   }
8471   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8472   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8473   if (csize) *csize = size;
8474   *values = array;
8475   PetscFunctionReturn(0);
8476 }
8477 
8478 #undef __FUNCT__
8479 #define __FUNCT__ "DMPlexVecRestoreClosure"
8480 /*@C
8481   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8482 
8483   Not collective
8484 
8485   Input Parameters:
8486 + dm - The DM
8487 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8488 . v - The local vector
8489 . point - The sieve point in the DM
8490 . csize - The number of values in the closure, or PETSC_NULL
8491 - values - The array of values, which is a borrowed array and should not be freed
8492 
8493   Level: intermediate
8494 
8495 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8496 @*/
8497 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8498 {
8499   PetscInt       size = 0;
8500   PetscErrorCode ierr;
8501 
8502   PetscFunctionBegin;
8503   /* Should work without recalculating size */
8504   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8505   PetscFunctionReturn(0);
8506 }
8507 
8508 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8509 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8510 
8511 #undef __FUNCT__
8512 #define __FUNCT__ "updatePoint_private"
8513 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8514 {
8515   PetscInt        cdof;   /* The number of constraints on this point */
8516   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8517   PetscScalar    *a;
8518   PetscInt        off, cind = 0, k;
8519   PetscErrorCode  ierr;
8520 
8521   PetscFunctionBegin;
8522   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8523   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8524   a    = &array[off];
8525   if (!cdof || setBC) {
8526     if (orientation >= 0) {
8527       for (k = 0; k < dof; ++k) {
8528         fuse(&a[k], values[k]);
8529       }
8530     } else {
8531       for (k = 0; k < dof; ++k) {
8532         fuse(&a[k], values[dof-k-1]);
8533       }
8534     }
8535   } else {
8536     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8537     if (orientation >= 0) {
8538       for (k = 0; k < dof; ++k) {
8539         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8540         fuse(&a[k], values[k]);
8541       }
8542     } else {
8543       for (k = 0; k < dof; ++k) {
8544         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8545         fuse(&a[k], values[dof-k-1]);
8546       }
8547     }
8548   }
8549   PetscFunctionReturn(0);
8550 }
8551 
8552 #undef __FUNCT__
8553 #define __FUNCT__ "updatePointFields_private"
8554 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8555 {
8556   PetscScalar   *a;
8557   PetscInt       numFields, off, foff, f;
8558   PetscErrorCode ierr;
8559 
8560   PetscFunctionBegin;
8561   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8562   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8563   a    = &array[off];
8564   for (f = 0, foff = 0; f < numFields; ++f) {
8565     PetscInt        fdof, fcomp, fcdof;
8566     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8567     PetscInt        cind = 0, k, c;
8568 
8569     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8570     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8571     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8572     if (!fcdof || setBC) {
8573       if (orientation >= 0) {
8574         for (k = 0; k < fdof; ++k) {
8575           fuse(&a[foff+k], values[foffs[f]+k]);
8576         }
8577       } else {
8578         for (k = fdof/fcomp-1; k >= 0; --k) {
8579           for (c = 0; c < fcomp; ++c) {
8580             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8581           }
8582         }
8583       }
8584     } else {
8585       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8586       if (orientation >= 0) {
8587         for (k = 0; k < fdof; ++k) {
8588           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8589           fuse(&a[foff+k], values[foffs[f]+k]);
8590         }
8591       } else {
8592         for (k = fdof/fcomp-1; k >= 0; --k) {
8593           for (c = 0; c < fcomp; ++c) {
8594             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8595             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8596           }
8597         }
8598       }
8599     }
8600     foff     += fdof;
8601     foffs[f] += fdof;
8602   }
8603   PetscFunctionReturn(0);
8604 }
8605 
8606 #undef __FUNCT__
8607 #define __FUNCT__ "DMPlexVecSetClosure"
8608 /*@C
8609   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8610 
8611   Not collective
8612 
8613   Input Parameters:
8614 + dm - The DM
8615 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8616 . v - The local vector
8617 . point - The sieve point in the DM
8618 . values - The array of values, which is a borrowed array and should not be freed
8619 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8620 
8621   Level: intermediate
8622 
8623 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8624 @*/
8625 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8626 {
8627   PetscScalar   *array;
8628   PetscInt      *points = PETSC_NULL;
8629   PetscInt       offsets[32];
8630   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8631   PetscErrorCode ierr;
8632 
8633   PetscFunctionBegin;
8634   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8635   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8636   if (!section) {
8637     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8638   }
8639   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8640   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8641   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8642   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8643   /* Compress out points not in the section */
8644   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8645   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8646     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8647       points[q*2]   = points[p];
8648       points[q*2+1] = points[p+1];
8649       ++q;
8650     }
8651   }
8652   numPoints = q;
8653   for (p = 0; p < numPoints*2; p += 2) {
8654     PetscInt fdof;
8655 
8656     for (f = 0; f < numFields; ++f) {
8657       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8658       offsets[f+1] += fdof;
8659     }
8660   }
8661   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8662   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8663   if (numFields) {
8664     switch (mode) {
8665     case INSERT_VALUES:
8666       for (p = 0; p < numPoints*2; p += 2) {
8667         PetscInt o = points[p+1];
8668         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8669       } break;
8670     case INSERT_ALL_VALUES:
8671       for (p = 0; p < numPoints*2; p += 2) {
8672         PetscInt o = points[p+1];
8673         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8674       } break;
8675     case ADD_VALUES:
8676       for (p = 0; p < numPoints*2; p += 2) {
8677         PetscInt o = points[p+1];
8678         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8679       } break;
8680     case ADD_ALL_VALUES:
8681       for (p = 0; p < numPoints*2; p += 2) {
8682         PetscInt o = points[p+1];
8683         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8684       } break;
8685     default:
8686       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8687     }
8688   } else {
8689     switch (mode) {
8690     case INSERT_VALUES:
8691       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8692         PetscInt o = points[p+1];
8693         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8694         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8695       } break;
8696     case INSERT_ALL_VALUES:
8697       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8698         PetscInt o = points[p+1];
8699         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8700         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8701       } break;
8702     case ADD_VALUES:
8703       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8704         PetscInt o = points[p+1];
8705         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8706         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8707       } break;
8708     case ADD_ALL_VALUES:
8709       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8710         PetscInt o = points[p+1];
8711         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8712         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8713       } break;
8714     default:
8715       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8716     }
8717   }
8718   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8719   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8720   PetscFunctionReturn(0);
8721 }
8722 
8723 #undef __FUNCT__
8724 #define __FUNCT__ "DMPlexPrintMatSetValues"
8725 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8726 {
8727   PetscMPIInt    rank;
8728   PetscInt       i, j;
8729   PetscErrorCode ierr;
8730 
8731   PetscFunctionBegin;
8732   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8733   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8734   for (i = 0; i < numIndices; i++) {
8735     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8736   }
8737   for (i = 0; i < numIndices; i++) {
8738     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8739     for (j = 0; j < numIndices; j++) {
8740 #if defined(PETSC_USE_COMPLEX)
8741       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8742 #else
8743       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8744 #endif
8745     }
8746     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8747   }
8748   PetscFunctionReturn(0);
8749 }
8750 
8751 #undef __FUNCT__
8752 #define __FUNCT__ "indicesPoint_private"
8753 /* . off - The global offset of this point */
8754 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8755 {
8756   PetscInt        cdof;   /* The number of constraints on this point */
8757   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8758   PetscInt        cind = 0, k;
8759   PetscErrorCode  ierr;
8760 
8761   PetscFunctionBegin;
8762   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8763   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8764   if (!cdof || setBC) {
8765     if (orientation >= 0) {
8766       for (k = 0; k < dof; ++k) indices[k] = off+k;
8767     } else {
8768       for (k = 0; k < dof; ++k) indices[dof-k-1] = off+k;
8769     }
8770   } else {
8771     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8772     if (orientation >= 0) {
8773       for (k = 0; k < dof; ++k) {
8774         if ((cind < cdof) && (k == cdofs[cind])) {
8775           /* Insert check for returning constrained indices */
8776           indices[k] = -(off+k+1);
8777           ++cind;
8778         } else {
8779           indices[k] = off+k-cind;
8780         }
8781       }
8782     } else {
8783       for (k = 0; k < dof; ++k) {
8784         if ((cind < cdof) && (k == cdofs[cind])) {
8785           /* Insert check for returning constrained indices */
8786           indices[dof-k-1] = -(off+k+1);
8787           ++cind;
8788         } else {
8789           indices[dof-k-1] = off+k-cind;
8790         }
8791       }
8792     }
8793   }
8794   PetscFunctionReturn(0);
8795 }
8796 
8797 #undef __FUNCT__
8798 #define __FUNCT__ "indicesPointFields_private"
8799 /* . off - The global offset of this point */
8800 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8801 {
8802   PetscInt       numFields, foff, f;
8803   PetscErrorCode ierr;
8804 
8805   PetscFunctionBegin;
8806   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8807   for (f = 0, foff = 0; f < numFields; ++f) {
8808     PetscInt        fdof, fcomp, cfdof;
8809     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8810     PetscInt        cind = 0, k, c;
8811 
8812     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8813     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8814     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
8815     if (!cfdof || setBC) {
8816       if (orientation >= 0) {
8817         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
8818       } else {
8819         for (k = fdof/fcomp-1; k >= 0; --k) {
8820           for (c = 0; c < fcomp; ++c) {
8821             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
8822           }
8823         }
8824       }
8825     } else {
8826       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8827       if (orientation >= 0) {
8828         for (k = 0; k < fdof; ++k) {
8829           if ((cind < cfdof) && (k == fcdofs[cind])) {
8830             indices[foffs[f]+k] = -(off+foff+k+1);
8831             ++cind;
8832           } else {
8833             indices[foffs[f]+k] = off+foff+k-cind;
8834           }
8835         }
8836       } else {
8837         for (k = fdof/fcomp-1; k >= 0; --k) {
8838           for (c = 0; c < fcomp; ++c) {
8839             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
8840               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
8841               ++cind;
8842             } else {
8843               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
8844             }
8845           }
8846         }
8847       }
8848     }
8849     foff     += fdof - cfdof;
8850     foffs[f] += fdof;
8851   }
8852   PetscFunctionReturn(0);
8853 }
8854 
8855 #undef __FUNCT__
8856 #define __FUNCT__ "DMPlexMatSetClosure"
8857 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
8858 {
8859   DM_Plex       *mesh   = (DM_Plex*) dm->data;
8860   PetscInt      *points = PETSC_NULL;
8861   PetscInt      *indices;
8862   PetscInt       offsets[32];
8863   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
8864   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
8865   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
8866   PetscErrorCode ierr;
8867 
8868   PetscFunctionBegin;
8869   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8870   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
8871   if (useDefault) {
8872     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8873   }
8874   if (useGlobalDefault) {
8875     if (useDefault) {
8876       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
8877     } else {
8878       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
8879     }
8880   }
8881   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8882   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8883   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8884   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8885   /* Compress out points not in the section */
8886   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8887   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8888     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8889       points[q*2]   = points[p];
8890       points[q*2+1] = points[p+1];
8891       ++q;
8892     }
8893   }
8894   numPoints = q;
8895   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8896     PetscInt fdof;
8897 
8898     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8899     for (f = 0; f < numFields; ++f) {
8900       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8901       offsets[f+1] += fdof;
8902     }
8903     numIndices += dof;
8904   }
8905   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8906 
8907   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8908   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8909   if (numFields) {
8910     for (p = 0; p < numPoints*2; p += 2) {
8911       PetscInt o = points[p+1];
8912       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8913       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8914     }
8915   } else {
8916     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8917       PetscInt o = points[p+1];
8918       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8919       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8920     }
8921   }
8922   if (useGlobalDefault && !useDefault) {
8923     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8924   }
8925   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8926   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8927   if (ierr) {
8928     PetscMPIInt    rank;
8929     PetscErrorCode ierr2;
8930 
8931     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8932     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8933     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8934     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8935     CHKERRQ(ierr);
8936   }
8937   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8938   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8939   PetscFunctionReturn(0);
8940 }
8941 
8942 #undef __FUNCT__
8943 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8944 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8945 {
8946   PetscSection       coordSection;
8947   Vec                coordinates;
8948   const PetscScalar *coords;
8949   const PetscInt     dim = 2;
8950   PetscInt           d, f;
8951   PetscErrorCode     ierr;
8952 
8953   PetscFunctionBegin;
8954   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8955   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8956   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8957   if (v0) {
8958     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
8959   }
8960   if (J) {
8961     for (d = 0; d < dim; d++) {
8962       for (f = 0; f < dim; f++) {
8963         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8964       }
8965     }
8966     *detJ = J[0]*J[3] - J[1]*J[2];
8967 #if 0
8968     if (detJ < 0.0) {
8969       const PetscReal xLength = mesh->periodicity[0];
8970 
8971       if (xLength != 0.0) {
8972         PetscReal v0x = coords[0*dim+0];
8973 
8974         if (v0x == 0.0) v0x = v0[0] = xLength;
8975         for (f = 0; f < dim; f++) {
8976           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8977 
8978           J[0*dim+f] = 0.5*(px - v0x);
8979         }
8980       }
8981       detJ = J[0]*J[3] - J[1]*J[2];
8982     }
8983 #endif
8984     PetscLogFlops(8.0 + 3.0);
8985   }
8986   if (invJ) {
8987     const PetscReal invDet = 1.0/(*detJ);
8988 
8989     invJ[0] =  invDet*J[3];
8990     invJ[1] = -invDet*J[1];
8991     invJ[2] = -invDet*J[2];
8992     invJ[3] =  invDet*J[0];
8993     PetscLogFlops(5.0);
8994   }
8995   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8996   PetscFunctionReturn(0);
8997 }
8998 
8999 #undef __FUNCT__
9000 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9001 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9002 {
9003   PetscSection       coordSection;
9004   Vec                coordinates;
9005   const PetscScalar *coords;
9006   const PetscInt     dim = 2;
9007   PetscInt           d, f;
9008   PetscErrorCode     ierr;
9009 
9010   PetscFunctionBegin;
9011   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9012   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9013   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9014   if (v0) {
9015     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9016   }
9017   if (J) {
9018     for (d = 0; d < dim; d++) {
9019       for (f = 0; f < dim; f++) {
9020         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9021       }
9022     }
9023     *detJ = J[0]*J[3] - J[1]*J[2];
9024     PetscLogFlops(8.0 + 3.0);
9025   }
9026   if (invJ) {
9027     const PetscReal invDet = 1.0/(*detJ);
9028 
9029     invJ[0] =  invDet*J[3];
9030     invJ[1] = -invDet*J[1];
9031     invJ[2] = -invDet*J[2];
9032     invJ[3] =  invDet*J[0];
9033     PetscLogFlops(5.0);
9034   }
9035   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9036   PetscFunctionReturn(0);
9037 }
9038 
9039 #undef __FUNCT__
9040 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9041 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9042 {
9043   PetscSection       coordSection;
9044   Vec                coordinates;
9045   const PetscScalar *coords;
9046   const PetscInt     dim = 3;
9047   PetscInt           d, f;
9048   PetscErrorCode     ierr;
9049 
9050   PetscFunctionBegin;
9051   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9052   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9053   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9054   if (v0) {
9055     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9056   }
9057   if (J) {
9058     for (d = 0; d < dim; d++) {
9059       for (f = 0; f < dim; f++) {
9060         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9061       }
9062     }
9063     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9064     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9065              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9066              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9067     PetscLogFlops(18.0 + 12.0);
9068   }
9069   if (invJ) {
9070     const PetscReal invDet = 1.0/(*detJ);
9071 
9072     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9073     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9074     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9075     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9076     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9077     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9078     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9079     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9080     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9081     PetscLogFlops(37.0);
9082   }
9083   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9084   PetscFunctionReturn(0);
9085 }
9086 
9087 #undef __FUNCT__
9088 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9089 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9090 {
9091   PetscSection       coordSection;
9092   Vec                coordinates;
9093   const PetscScalar *coords;
9094   const PetscInt     dim = 3;
9095   PetscInt           d;
9096   PetscErrorCode     ierr;
9097 
9098   PetscFunctionBegin;
9099   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9100   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9101   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9102   if (v0) {
9103     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9104   }
9105   if (J) {
9106     for (d = 0; d < dim; d++) {
9107       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9108       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9109       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9110     }
9111     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9112              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9113              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9114     PetscLogFlops(18.0 + 12.0);
9115   }
9116   if (invJ) {
9117     const PetscReal invDet = -1.0/(*detJ);
9118 
9119     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9120     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9121     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9122     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9123     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9124     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9125     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9126     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9127     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9128     PetscLogFlops(37.0);
9129   }
9130   *detJ *= 8.0;
9131   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9132   PetscFunctionReturn(0);
9133 }
9134 
9135 #undef __FUNCT__
9136 #define __FUNCT__ "DMPlexComputeCellGeometry"
9137 /*@C
9138   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9139 
9140   Collective on DM
9141 
9142   Input Arguments:
9143 + dm   - the DM
9144 - cell - the cell
9145 
9146   Output Arguments:
9147 + v0   - the translation part of this affine transform
9148 . J    - the Jacobian of the transform to the reference element
9149 . invJ - the inverse of the Jacobian
9150 - detJ - the Jacobian determinant
9151 
9152   Level: advanced
9153 
9154 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9155 @*/
9156 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9157 {
9158   PetscInt       dim, coneSize;
9159   PetscErrorCode ierr;
9160 
9161   PetscFunctionBegin;
9162   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9163   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9164   switch (dim) {
9165   case 2:
9166     switch (coneSize) {
9167     case 3:
9168       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9169       break;
9170     case 4:
9171       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9172       break;
9173     default:
9174       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9175     }
9176     break;
9177   case 3:
9178     switch (coneSize) {
9179     case 4:
9180       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9181       break;
9182     case 8:
9183       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9184       break;
9185     default:
9186       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9187     }
9188     break;
9189   default:
9190     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9191   }
9192   PetscFunctionReturn(0);
9193 }
9194 
9195 #undef __FUNCT__
9196 #define __FUNCT__ "DMPlexGetFaceOrientation"
9197 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9198 {
9199   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9200   PetscBool      posOrient = PETSC_FALSE;
9201   const PetscInt debug     = 0;
9202   PetscInt       cellDim, faceSize, f;
9203   PetscErrorCode ierr;
9204 
9205   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9206   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9207 
9208   if (cellDim == numCorners-1) {
9209     /* Simplices */
9210     faceSize  = numCorners-1;
9211     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9212   } else if (cellDim == 1 && numCorners == 3) {
9213     /* Quadratic line */
9214     faceSize  = 1;
9215     posOrient = PETSC_TRUE;
9216   } else if (cellDim == 2 && numCorners == 4) {
9217     /* Quads */
9218     faceSize = 2;
9219     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9220       posOrient = PETSC_TRUE;
9221     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9222       posOrient = PETSC_TRUE;
9223     } else {
9224       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9225         posOrient = PETSC_FALSE;
9226       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9227     }
9228   } else if (cellDim == 2 && numCorners == 6) {
9229     /* Quadratic triangle (I hate this) */
9230     /* Edges are determined by the first 2 vertices (corners of edges) */
9231     const PetscInt faceSizeTri = 3;
9232     PetscInt       sortedIndices[3], i, iFace;
9233     PetscBool      found                    = PETSC_FALSE;
9234     PetscInt       faceVerticesTriSorted[9] = {
9235       0, 3,  4, /* bottom */
9236       1, 4,  5, /* right */
9237       2, 3,  5, /* left */
9238     };
9239     PetscInt       faceVerticesTri[9] = {
9240       0, 3,  4, /* bottom */
9241       1, 4,  5, /* right */
9242       2, 5,  3, /* left */
9243     };
9244 
9245     faceSize = faceSizeTri;
9246     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9247     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9248     for (iFace = 0; iFace < 3; ++iFace) {
9249       const PetscInt ii = iFace*faceSizeTri;
9250       PetscInt       fVertex, cVertex;
9251 
9252       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9253           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9254         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9255           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9256             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9257               faceVertices[fVertex] = origVertices[cVertex];
9258               break;
9259             }
9260           }
9261         }
9262         found = PETSC_TRUE;
9263         break;
9264       }
9265     }
9266     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9267     if (posOriented) *posOriented = PETSC_TRUE;
9268     PetscFunctionReturn(0);
9269   } else if (cellDim == 2 && numCorners == 9) {
9270     /* Quadratic quad (I hate this) */
9271     /* Edges are determined by the first 2 vertices (corners of edges) */
9272     const PetscInt faceSizeQuad = 3;
9273     PetscInt       sortedIndices[3], i, iFace;
9274     PetscBool      found                      = PETSC_FALSE;
9275     PetscInt       faceVerticesQuadSorted[12] = {
9276       0, 1,  4, /* bottom */
9277       1, 2,  5, /* right */
9278       2, 3,  6, /* top */
9279       0, 3,  7, /* left */
9280     };
9281     PetscInt       faceVerticesQuad[12] = {
9282       0, 1,  4, /* bottom */
9283       1, 2,  5, /* right */
9284       2, 3,  6, /* top */
9285       3, 0,  7, /* left */
9286     };
9287 
9288     faceSize = faceSizeQuad;
9289     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9290     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9291     for (iFace = 0; iFace < 4; ++iFace) {
9292       const PetscInt ii = iFace*faceSizeQuad;
9293       PetscInt       fVertex, cVertex;
9294 
9295       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9296           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9297         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9298           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9299             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9300               faceVertices[fVertex] = origVertices[cVertex];
9301               break;
9302             }
9303           }
9304         }
9305         found = PETSC_TRUE;
9306         break;
9307       }
9308     }
9309     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9310     if (posOriented) *posOriented = PETSC_TRUE;
9311     PetscFunctionReturn(0);
9312   } else if (cellDim == 3 && numCorners == 8) {
9313     /* Hexes
9314        A hex is two oriented quads with the normal of the first
9315        pointing up at the second.
9316 
9317           7---6
9318          /|  /|
9319         4---5 |
9320         | 3-|-2
9321         |/  |/
9322         0---1
9323 
9324         Faces are determined by the first 4 vertices (corners of faces) */
9325     const PetscInt faceSizeHex = 4;
9326     PetscInt       sortedIndices[4], i, iFace;
9327     PetscBool      found                     = PETSC_FALSE;
9328     PetscInt       faceVerticesHexSorted[24] = {
9329       0, 1, 2, 3,  /* bottom */
9330       4, 5, 6, 7,  /* top */
9331       0, 1, 4, 5,  /* front */
9332       1, 2, 5, 6,  /* right */
9333       2, 3, 6, 7,  /* back */
9334       0, 3, 4, 7,  /* left */
9335     };
9336     PetscInt       faceVerticesHex[24] = {
9337       3, 2, 1, 0,  /* bottom */
9338       4, 5, 6, 7,  /* top */
9339       0, 1, 5, 4,  /* front */
9340       1, 2, 6, 5,  /* right */
9341       2, 3, 7, 6,  /* back */
9342       3, 0, 4, 7,  /* left */
9343     };
9344 
9345     faceSize = faceSizeHex;
9346     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9347     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9348     for (iFace = 0; iFace < 6; ++iFace) {
9349       const PetscInt ii = iFace*faceSizeHex;
9350       PetscInt       fVertex, cVertex;
9351 
9352       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9353           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9354           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9355           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9356         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9357           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9358             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9359               faceVertices[fVertex] = origVertices[cVertex];
9360               break;
9361             }
9362           }
9363         }
9364         found = PETSC_TRUE;
9365         break;
9366       }
9367     }
9368     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9369     if (posOriented) *posOriented = PETSC_TRUE;
9370     PetscFunctionReturn(0);
9371   } else if (cellDim == 3 && numCorners == 10) {
9372     /* Quadratic tet */
9373     /* Faces are determined by the first 3 vertices (corners of faces) */
9374     const PetscInt faceSizeTet = 6;
9375     PetscInt       sortedIndices[6], i, iFace;
9376     PetscBool      found                     = PETSC_FALSE;
9377     PetscInt       faceVerticesTetSorted[24] = {
9378       0, 1, 2,  6, 7, 8, /* bottom */
9379       0, 3, 4,  6, 7, 9,  /* front */
9380       1, 4, 5,  7, 8, 9,  /* right */
9381       2, 3, 5,  6, 8, 9,  /* left */
9382     };
9383     PetscInt       faceVerticesTet[24] = {
9384       0, 1, 2,  6, 7, 8, /* bottom */
9385       0, 4, 3,  6, 7, 9,  /* front */
9386       1, 5, 4,  7, 8, 9,  /* right */
9387       2, 3, 5,  8, 6, 9,  /* left */
9388     };
9389 
9390     faceSize = faceSizeTet;
9391     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9392     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9393     for (iFace=0; iFace < 4; ++iFace) {
9394       const PetscInt ii = iFace*faceSizeTet;
9395       PetscInt       fVertex, cVertex;
9396 
9397       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9398           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9399           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9400           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9401         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9402           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9403             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9404               faceVertices[fVertex] = origVertices[cVertex];
9405               break;
9406             }
9407           }
9408         }
9409         found = PETSC_TRUE;
9410         break;
9411       }
9412     }
9413     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9414     if (posOriented) *posOriented = PETSC_TRUE;
9415     PetscFunctionReturn(0);
9416   } else if (cellDim == 3 && numCorners == 27) {
9417     /* Quadratic hexes (I hate this)
9418        A hex is two oriented quads with the normal of the first
9419        pointing up at the second.
9420 
9421          7---6
9422         /|  /|
9423        4---5 |
9424        | 3-|-2
9425        |/  |/
9426        0---1
9427 
9428        Faces are determined by the first 4 vertices (corners of faces) */
9429     const PetscInt faceSizeQuadHex = 9;
9430     PetscInt       sortedIndices[9], i, iFace;
9431     PetscBool      found                         = PETSC_FALSE;
9432     PetscInt       faceVerticesQuadHexSorted[54] = {
9433       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9434       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9435       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9436       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9437       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9438       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9439     };
9440     PetscInt       faceVerticesQuadHex[54] = {
9441       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9442       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9443       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9444       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9445       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9446       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9447     };
9448 
9449     faceSize = faceSizeQuadHex;
9450     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9451     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9452     for (iFace = 0; iFace < 6; ++iFace) {
9453       const PetscInt ii = iFace*faceSizeQuadHex;
9454       PetscInt       fVertex, cVertex;
9455 
9456       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9457           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9458           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9459           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9460         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9461           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9462             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9463               faceVertices[fVertex] = origVertices[cVertex];
9464               break;
9465             }
9466           }
9467         }
9468         found = PETSC_TRUE;
9469         break;
9470       }
9471     }
9472     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9473     if (posOriented) *posOriented = PETSC_TRUE;
9474     PetscFunctionReturn(0);
9475   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9476   if (!posOrient) {
9477     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9478     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize-1 - f];
9479   } else {
9480     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9481     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f];
9482   }
9483   if (posOriented) *posOriented = posOrient;
9484   PetscFunctionReturn(0);
9485 }
9486 
9487 #undef __FUNCT__
9488 #define __FUNCT__ "DMPlexGetOrientedFace"
9489 /*
9490     Given a cell and a face, as a set of vertices,
9491       return the oriented face, as a set of vertices, in faceVertices
9492     The orientation is such that the face normal points out of the cell
9493 */
9494 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9495 {
9496   const PetscInt *cone = PETSC_NULL;
9497   PetscInt        coneSize, v, f, v2;
9498   PetscInt        oppositeVertex = -1;
9499   PetscErrorCode  ierr;
9500 
9501   PetscFunctionBegin;
9502   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9503   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9504   for (v = 0, v2 = 0; v < coneSize; ++v) {
9505     PetscBool found = PETSC_FALSE;
9506 
9507     for (f = 0; f < faceSize; ++f) {
9508       if (face[f] == cone[v]) {
9509         found = PETSC_TRUE; break;
9510       }
9511     }
9512     if (found) {
9513       indices[v2]      = v;
9514       origVertices[v2] = cone[v];
9515       ++v2;
9516     } else {
9517       oppositeVertex = v;
9518     }
9519   }
9520   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9521   PetscFunctionReturn(0);
9522 }
9523 
9524 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9525 {
9526   switch (i) {
9527   case 0:
9528     switch (j) {
9529     case 0: return 0;
9530     case 1:
9531       switch (k) {
9532       case 0: return 0;
9533       case 1: return 0;
9534       case 2: return 1;
9535       }
9536     case 2:
9537       switch (k) {
9538       case 0: return 0;
9539       case 1: return -1;
9540       case 2: return 0;
9541       }
9542     }
9543   case 1:
9544     switch (j) {
9545     case 0:
9546       switch (k) {
9547       case 0: return 0;
9548       case 1: return 0;
9549       case 2: return -1;
9550       }
9551     case 1: return 0;
9552     case 2:
9553       switch (k) {
9554       case 0: return 1;
9555       case 1: return 0;
9556       case 2: return 0;
9557       }
9558     }
9559   case 2:
9560     switch (j) {
9561     case 0:
9562       switch (k) {
9563       case 0: return 0;
9564       case 1: return 1;
9565       case 2: return 0;
9566       }
9567     case 1:
9568       switch (k) {
9569       case 0: return -1;
9570       case 1: return 0;
9571       case 2: return 0;
9572       }
9573     case 2: return 0;
9574     }
9575   }
9576   return 0;
9577 }
9578 
9579 #undef __FUNCT__
9580 #define __FUNCT__ "DMPlexCreateRigidBody"
9581 /*@C
9582   DMPlexCreateRigidBody - create rigid body modes from coordinates
9583 
9584   Collective on DM
9585 
9586   Input Arguments:
9587 + dm - the DM
9588 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9589 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9590 
9591   Output Argument:
9592 . sp - the null space
9593 
9594   Note: This is necessary to take account of Dirichlet conditions on the displacements
9595 
9596   Level: advanced
9597 
9598 .seealso: MatNullSpaceCreate()
9599 @*/
9600 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9601 {
9602   MPI_Comm       comm = ((PetscObject) dm)->comm;
9603   Vec            coordinates, localMode, mode[6];
9604   PetscSection   coordSection;
9605   PetscScalar   *coords;
9606   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9607   PetscErrorCode ierr;
9608 
9609   PetscFunctionBegin;
9610   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9611   if (dim == 1) {
9612     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9613     PetscFunctionReturn(0);
9614   }
9615   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9616   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9617   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9618   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9619   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9620   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9621   m    = (dim*(dim+1))/2;
9622   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9623   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9624   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9625   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9626   /* Assume P1 */
9627   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9628   for (d = 0; d < dim; ++d) {
9629     PetscScalar values[3] = {0.0, 0.0, 0.0};
9630 
9631     values[d] = 1.0;
9632     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9633     for (v = vStart; v < vEnd; ++v) {
9634       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9635     }
9636     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9637     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9638   }
9639   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9640   for (d = dim; d < dim*(dim+1)/2; ++d) {
9641     PetscInt i, j, k = dim > 2 ? d - dim : d;
9642 
9643     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9644     for (v = vStart; v < vEnd; ++v) {
9645       PetscScalar values[3] = {0.0, 0.0, 0.0};
9646       PetscInt    off;
9647 
9648       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9649       for (i = 0; i < dim; ++i) {
9650         for (j = 0; j < dim; ++j) {
9651           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9652         }
9653       }
9654       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9655     }
9656     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9657     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9658   }
9659   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9660   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9661   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9662   /* Orthonormalize system */
9663   for (i = dim; i < m; ++i) {
9664     PetscScalar dots[6];
9665 
9666     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9667     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9668     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9669     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9670   }
9671   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9672   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9673   PetscFunctionReturn(0);
9674 }
9675 
9676 #undef __FUNCT__
9677 #define __FUNCT__ "DMPlexGetHybridBounds"
9678 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9679 {
9680   DM_Plex       *mesh = (DM_Plex*) dm->data;
9681   PetscInt       dim;
9682   PetscErrorCode ierr;
9683 
9684   PetscFunctionBegin;
9685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9686   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9687   if (cMax) *cMax = mesh->hybridPointMax[dim];
9688   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9689   if (eMax) *eMax = mesh->hybridPointMax[1];
9690   if (vMax) *vMax = mesh->hybridPointMax[0];
9691   PetscFunctionReturn(0);
9692 }
9693 
9694 #undef __FUNCT__
9695 #define __FUNCT__ "DMPlexSetHybridBounds"
9696 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9697 {
9698   DM_Plex       *mesh = (DM_Plex*) dm->data;
9699   PetscInt       dim;
9700   PetscErrorCode ierr;
9701 
9702   PetscFunctionBegin;
9703   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9704   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9705   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9706   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9707   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9708   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9709   PetscFunctionReturn(0);
9710 }
9711 
9712 #undef __FUNCT__
9713 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9714 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9715 {
9716   DM_Plex *mesh = (DM_Plex*) dm->data;
9717 
9718   PetscFunctionBegin;
9719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9720   PetscValidPointer(cellHeight, 2);
9721   *cellHeight = mesh->vtkCellHeight;
9722   PetscFunctionReturn(0);
9723 }
9724 
9725 #undef __FUNCT__
9726 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9727 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9728 {
9729   DM_Plex *mesh = (DM_Plex*) dm->data;
9730 
9731   PetscFunctionBegin;
9732   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9733   mesh->vtkCellHeight = cellHeight;
9734   PetscFunctionReturn(0);
9735 }
9736 
9737 #undef __FUNCT__
9738 #define __FUNCT__ "DMPlexInsertFace_Private"
9739 /*
9740   DMPlexInsertFace_Private - Puts a face into the mesh
9741 
9742   Not collective
9743 
9744   Input Parameters:
9745   + dm              - The DMPlex
9746   . numFaceVertex   - The number of vertices in the face
9747   . faceVertices    - The vertices in the face for dm
9748   . subfaceVertices - The vertices in the face for subdm
9749   . numCorners      - The number of vertices in the cell
9750   . cell            - A cell in dm containing the face
9751   . subcell         - A cell in subdm containing the face
9752   . firstFace       - First face in the mesh
9753   - newFacePoint    - Next face in the mesh
9754 
9755   Output Parameters:
9756   . newFacePoint - Contains next face point number on input, updated on output
9757 
9758   Level: developer
9759 */
9760 PetscErrorCode DMPlexInsertFace_Private(DM dm, DM subdm, PetscInt numFaceVertices, const PetscInt faceVertices[], const PetscInt subfaceVertices[], PetscInt numCorners, PetscInt cell, PetscInt subcell, PetscInt firstFace, PetscInt *newFacePoint)
9761 {
9762   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9763   DM_Plex        *submesh = (DM_Plex*) subdm->data;
9764   const PetscInt *faces;
9765   PetscInt        numFaces, coneSize;
9766   PetscErrorCode  ierr;
9767 
9768   PetscFunctionBegin;
9769   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9770   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9771 #if 0
9772   /* Cannot use this because support() has not been constructed yet */
9773   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9774 #else
9775   {
9776     PetscInt f;
9777 
9778     numFaces = 0;
9779     ierr     = DMGetWorkArray(subdm, 1, PETSC_INT, (void**) &faces);CHKERRQ(ierr);
9780     for (f = firstFace; f < *newFacePoint; ++f) {
9781       PetscInt dof, off, d;
9782 
9783       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9784       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9785       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9786       for (d = 0; d < dof; ++d) {
9787         const PetscInt p = submesh->cones[off+d];
9788         PetscInt       v;
9789 
9790         for (v = 0; v < numFaceVertices; ++v) {
9791           if (subfaceVertices[v] == p) break;
9792         }
9793         if (v == numFaceVertices) break;
9794       }
9795       if (d == dof) {
9796         numFaces               = 1;
9797         ((PetscInt*) faces)[0] = f;
9798       }
9799     }
9800   }
9801 #endif
9802   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
9803   else if (numFaces == 1) {
9804     /* Add the other cell neighbor for this face */
9805     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
9806   } else {
9807     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
9808     PetscBool posOriented;
9809 
9810     ierr                = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9811     origVertices        = &orientedVertices[numFaceVertices];
9812     indices             = &orientedVertices[numFaceVertices*2];
9813     orientedSubVertices = &orientedVertices[numFaceVertices*3];
9814     ierr                = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
9815     /* TODO: I know that routine should return a permutation, not the indices */
9816     for (v = 0; v < numFaceVertices; ++v) {
9817       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
9818       for (ov = 0; ov < numFaceVertices; ++ov) {
9819         if (orientedVertices[ov] == vertex) {
9820           orientedSubVertices[ov] = subvertex;
9821           break;
9822         }
9823       }
9824       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
9825     }
9826     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
9827     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
9828     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
9829     ++(*newFacePoint);
9830   }
9831   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9832   PetscFunctionReturn(0);
9833 }
9834 
9835 #undef __FUNCT__
9836 #define __FUNCT__ "DMPlexCreateSubmesh_Uninterpolated"
9837 static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, const char label[], const char surfaceLabel[], DM subdm)
9838 {
9839   MPI_Comm        comm = ((PetscObject) dm)->comm;
9840   PetscBool       boundaryFaces = PETSC_FALSE;
9841   PetscSection    coordSection, subCoordSection;
9842   Vec             coordinates, subCoordinates;
9843   PetscScalar    *coords, *subCoords;
9844   IS              labelIS, subpointMap;
9845   const PetscInt *subVertices;
9846   PetscInt       *subVerticesActive, *tmpPoints;
9847   PetscInt       *subCells = PETSC_NULL;
9848   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
9849   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
9850   PetscInt        dim;  /* Right now, do not specify dimension */
9851   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
9852   PetscErrorCode  ierr;
9853 
9854   PetscFunctionBegin;
9855   if (surfaceLabel) SETERRQ(comm, PETSC_ERR_SUP, "Yell at me to do this");
9856   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9857   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9858   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9859   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
9860   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
9861   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
9862   if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
9863   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9864   subface = &face[maxConeSize];
9865   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
9866   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
9867   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
9868   maxSubCells = numSubVertices;
9869   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
9870   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
9871   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
9872   for (v = 0; v < numSubVertices; ++v) {
9873     const PetscInt vertex = subVertices[v];
9874     PetscInt      *star   = PETSC_NULL;
9875     PetscInt       starSize, numCells = 0;
9876 
9877     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9878     for (p = 0; p < starSize*2; p += 2) {
9879       const PetscInt point = star[p];
9880       if ((point >= cStart) && (point < cEnd)) star[numCells++] = point;
9881     }
9882     numOldSubCells = numSubCells;
9883     for (c = 0; c < numCells; ++c) {
9884       const PetscInt cell    = star[c];
9885       PetscInt      *closure = PETSC_NULL;
9886       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9887       PetscInt       cellLoc;
9888 
9889       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9890       if (cellLoc >= 0) continue;
9891       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9892       for (p = 0; p < closureSize*2; p += 2) {
9893         const PetscInt point = closure[p];
9894         if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
9895       }
9896       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9897       for (corner = 0; corner < numCorners; ++corner) {
9898         const PetscInt cellVertex = closure[corner];
9899         PetscInt       subVertex;
9900 
9901         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9902         if (subVertex >= 0) { /* contains submesh vertex */
9903           for (i = 0; i < faceSize; ++i) {
9904             if (cellVertex == face[i]) break;
9905           }
9906           if (i == faceSize) {
9907             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9908             face[faceSize]    = cellVertex;
9909             subface[faceSize] = subVertex;
9910             ++faceSize;
9911           }
9912         }
9913       }
9914       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9915       if (faceSize >= nFV) {
9916         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9917         if (numSubCells >= maxSubCells) {
9918           PetscInt *tmpCells;
9919           maxSubCells *= 2;
9920           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9921           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9922           ierr = PetscFree(subCells);CHKERRQ(ierr);
9923 
9924           subCells = tmpCells;
9925         }
9926         /* TOOD: Maybe overestimate then squeeze out empty faces */
9927         if (faceSize > nFV) {
9928           /* TODO: This is tricky. Maybe just add all faces */
9929           numSubFaces++;
9930         } else {
9931           numSubFaces++;
9932         }
9933         for (f = 0; f < faceSize; ++f) subVerticesActive[subface[f]] = 1;
9934         subCells[numSubCells++] = cell;
9935       }
9936     }
9937     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9938     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9939   }
9940   /* Pick out active subvertices */
9941   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9942     if (subVerticesActive[v]) {
9943       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9944     }
9945   }
9946   ierr = DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9947   /* Set cone sizes */
9948   firstSubVertex = numSubCells;
9949   firstSubFace   = numSubCells+numSubVerticesActive;
9950   newFacePoint   = firstSubFace;
9951   for (c = 0; c < numSubCells; ++c) {
9952     ierr = DMPlexSetConeSize(subdm, c, 1);CHKERRQ(ierr);
9953   }
9954   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9955     ierr = DMPlexSetConeSize(subdm, f, nFV);CHKERRQ(ierr);
9956   }
9957   ierr = DMSetUp(subdm);CHKERRQ(ierr);
9958   /* Create face cones */
9959   for (c = 0; c < numSubCells; ++c) {
9960     const PetscInt cell    = subCells[c];
9961     PetscInt      *closure = PETSC_NULL;
9962     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9963 
9964     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9965     for (p = 0; p < closureSize*2; p += 2) {
9966       const PetscInt point = closure[p];
9967       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
9968     }
9969     for (corner = 0; corner < numCorners; ++corner) {
9970       const PetscInt cellVertex = closure[corner];
9971       PetscInt       subVertex;
9972 
9973       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9974       if (subVertex >= 0) { /* contains submesh vertex */
9975         for (i = 0; i < faceSize; ++i) {
9976           if (cellVertex == face[i]) break;
9977         }
9978         if (i == faceSize) {
9979           face[faceSize]    = cellVertex;
9980           subface[faceSize] = numSubCells+subVertex;
9981           ++faceSize;
9982         }
9983       }
9984     }
9985     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9986     if (faceSize >= nFV) {
9987       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9988       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
9989       /*   We have to take all the faces, and discard those in the interior */
9990       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
9991 #if 0
9992       /* This object just calls insert on each face that comes from subsets() */
9993       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
9994       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9995       PointArray                          faceVec(face->begin(), face->end());
9996 
9997       subsets(faceVec, nFV, inserter);
9998 #endif
9999       ierr = DMPlexInsertFace_Private(dm, subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10000     }
10001   }
10002   ierr = DMPlexSymmetrize(subdm);CHKERRQ(ierr);
10003   ierr = DMPlexStratify(subdm);CHKERRQ(ierr);
10004   /* Build coordinates */
10005   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10006   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10007   ierr = DMPlexGetCoordinateSection(subdm, &subCoordSection);CHKERRQ(ierr);
10008   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10009   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10010     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10011   }
10012   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10013   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10014   ierr = VecCreate(comm, &subCoordinates);CHKERRQ(ierr);
10015   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10016   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10017   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10018   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10019   for (v = 0; v < numSubVerticesActive; ++v) {
10020     const PetscInt vertex    = subVerticesActive[v];
10021     const PetscInt subVertex = firstSubVertex+v;
10022     PetscInt       dof, off, sdof, soff;
10023 
10024     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10025     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10026     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10027     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10028     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10029     for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
10030   }
10031   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10032   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10033   ierr = DMSetCoordinatesLocal(subdm, subCoordinates);CHKERRQ(ierr);
10034   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10035 
10036   ierr = DMPlexSetVTKCellHeight(subdm, 1);CHKERRQ(ierr);
10037   /* Create map from submesh points to original mesh points */
10038   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10039   for (c = 0; c < numSubCells; ++c) tmpPoints[c] = subCells[c];
10040   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) tmpPoints[v] = subVerticesActive[v-numSubCells];
10041   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &subpointMap);CHKERRQ(ierr);
10042   ierr = DMPlexSetSubpointMap(subdm, subpointMap);CHKERRQ(ierr);
10043   ierr = ISDestroy(&subpointMap);CHKERRQ(ierr);
10044 
10045   ierr = PetscFree(subCells);CHKERRQ(ierr);
10046   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10047   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10048   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10049   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10050   PetscFunctionReturn(0);
10051 }
10052 
10053 #undef __FUNCT__
10054 #define __FUNCT__ "DMPlexCreateSubmesh_Interpolated"
10055 static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, const char vertexLabel[], const char surfaceLabel[], DM subdm)
10056 {
10057   MPI_Comm        comm = ((PetscObject) dm)->comm;
10058   const char     *name = surfaceLabel ? surfaceLabel : "submesh_label";
10059   DMLabel         slabel;
10060   IS              subvertexIS, subedgeIS, subfaceIS, subcellIS, subpointMap;
10061   const PetscInt *subVertices, *subEdges, *subFaces, *subCells;
10062   PetscInt       *numSubPoints, *coneNew;
10063   PetscInt        dim, numSubVerticesInitial, numSubVertices, firstSubVertex, v, numSubEdges = 0, firstSubEdge, e, numSubFaces = 0, firstSubFace, f, numSubCells;
10064   PetscInt        vStart, vEnd, fStart, fEnd;
10065   PetscErrorCode  ierr;
10066 
10067   PetscFunctionBegin;
10068   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10069   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10070   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
10071   ierr = DMPlexCreateLabel(subdm, name);CHKERRQ(ierr);
10072   ierr = DMPlexGetLabel(subdm, name, &slabel);CHKERRQ(ierr);
10073   ierr = DMPlexGetStratumIS(dm, vertexLabel, 1, &subvertexIS);CHKERRQ(ierr);
10074   ierr = ISGetSize(subvertexIS, &numSubVerticesInitial);CHKERRQ(ierr);
10075   ierr = ISGetIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10076   for (v = 0; v < numSubVerticesInitial; ++v) {
10077     const PetscInt vertex = subVertices[v];
10078     PetscInt *star = PETSC_NULL;
10079     PetscInt  starSize, s, numFaces = 0, f;
10080 
10081     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10082     for (s = 0; s < starSize*2; s += 2) {
10083       const PetscInt point = star[s];
10084       if ((point >= fStart) && (point < fEnd)) {
10085         star[numFaces++] = point;
10086       }
10087     }
10088     for (f = 0; f < numFaces; ++f) {
10089       const PetscInt face    = star[f];
10090       PetscInt      *closure = PETSC_NULL;
10091       PetscInt       closureSize, c, numCorners = 0;
10092       PetscInt       faceLoc, corner;
10093 
10094       ierr = DMLabelGetValue(slabel, face, &faceLoc);CHKERRQ(ierr);
10095       if (faceLoc == dim-1) continue;
10096       if (faceLoc >= 0) SETERRQ2(comm, PETSC_ERR_PLIB, "Face %d has dimension %d in the surface label", face, faceLoc);
10097       ierr = DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10098       for (c = 0; c < closureSize*2; c += 2) {
10099         const PetscInt point = closure[c];
10100         if ((point >= vStart) && (point < vEnd)) {
10101           closure[numCorners++] = point;
10102         }
10103       }
10104       for (corner = 0; corner < numCorners; ++corner) {
10105         const PetscInt cellVertex = closure[corner];
10106         PetscInt       vertexLoc;
10107 
10108         ierr = DMLabelGetValue(slabel, cellVertex, &vertexLoc);CHKERRQ(ierr);
10109         if (vertexLoc < 0) break;
10110       }
10111       ierr = DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10112       if (corner == numCorners) {
10113         const PetscInt *support;
10114         PetscInt        supportSize;
10115 
10116         for (corner = 0; corner < numCorners; ++corner) {ierr = DMLabelSetValue(slabel, closure[corner], 0);CHKERRQ(ierr);}
10117         ierr = DMLabelSetValue(slabel, face, dim-1);CHKERRQ(ierr);
10118         ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10119         ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10120         for(s = 0; s < supportSize; ++s) {
10121           ierr = DMLabelSetValue(slabel, support[s], dim);CHKERRQ(ierr);
10122         }
10123         if (dim > 2) {
10124           const PetscInt *cone;
10125           PetscInt        coneSize;
10126 
10127           ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10128           ierr = DMPlexGetCone(dm, face, &cone);CHKERRQ(ierr);
10129           for(c = 0; c < coneSize; ++c) {
10130             ierr = DMLabelSetValue(slabel, cone[c], dim-2);CHKERRQ(ierr);
10131           }
10132         }
10133       }
10134     }
10135     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10136   }
10137   ierr = ISRestoreIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10138   ierr = ISDestroy(&subvertexIS);CHKERRQ(ierr);
10139   ierr = DMLabelGetStratumSize(slabel, dim,   &numSubCells);CHKERRQ(ierr);
10140   ierr = DMLabelGetStratumSize(slabel, 0,     &numSubVertices);CHKERRQ(ierr);
10141   if (dim > 1) {ierr = DMLabelGetStratumSize(slabel, dim-1, &numSubFaces);CHKERRQ(ierr);}
10142   if (dim > 2) {ierr = DMLabelGetStratumSize(slabel, 1,     &numSubEdges);CHKERRQ(ierr);}
10143   ierr = DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubEdges+numSubVertices);CHKERRQ(ierr);
10144   ierr = DMPlexSetVTKCellHeight(subdm, 1);CHKERRQ(ierr);
10145   /* Set cone sizes */
10146   firstSubVertex = numSubCells;
10147   firstSubFace   = firstSubVertex + numSubVertices;
10148   firstSubEdge   = firstSubFace   + numSubFaces;
10149   ierr = DMLabelGetStratumIS(slabel, dim,   &subcellIS);CHKERRQ(ierr);
10150   ierr = ISGetIndices(subcellIS, &subCells);CHKERRQ(ierr);
10151   ierr = DMLabelGetStratumIS(slabel, 0,     &subvertexIS);CHKERRQ(ierr);
10152   ierr = ISGetIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10153   if (dim > 1) {
10154     ierr = DMLabelGetStratumIS(slabel, dim-1, &subfaceIS);CHKERRQ(ierr);
10155     ierr = ISGetIndices(subfaceIS, &subFaces);CHKERRQ(ierr);
10156   }
10157   if (dim > 2) {
10158     ierr = DMLabelGetStratumIS(slabel, 1,     &subedgeIS);CHKERRQ(ierr);
10159     ierr = ISGetIndices(subedgeIS, &subEdges);CHKERRQ(ierr);
10160   }
10161   for (e = firstSubEdge; e < firstSubEdge+numSubEdges; ++e) {
10162     ierr = DMPlexSetConeSize(subdm, e, 2);CHKERRQ(ierr);
10163   }
10164   for (f = 0; f < numSubFaces; ++f) {
10165     const PetscInt  face    = subFaces[f];
10166     const PetscInt  subface = firstSubFace + f;
10167     const PetscInt *support;
10168     PetscInt        coneSize, supportSize, subcell, s;
10169 
10170     ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10171     ierr = DMPlexSetConeSize(subdm, subface, coneSize);CHKERRQ(ierr);
10172     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10173     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10174     for(s = 0; s < supportSize; ++s) {
10175       ierr = PetscFindInt(support[s], numSubCells, subCells, &subcell);CHKERRQ(ierr);
10176       if (subcell < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Subcell %d not found in surface label", support[s]);
10177       /* ierr = DMPlexAddConeSize(subdm, subcell, 1);CHKERRQ(ierr); */
10178     }
10179   }
10180   ierr = DMSetUp(subdm);CHKERRQ(ierr);
10181   /* Set cones */
10182   for (e = 0; e < numSubEdges; ++e) {
10183     const PetscInt  edge    = subEdges[e];
10184     const PetscInt  subedge = firstSubEdge + e;
10185     const PetscInt *cone;
10186     PetscInt        coneSize, c, coneNew[2], subv;
10187 
10188     ierr = DMPlexGetConeSize(subdm, e, &coneSize);CHKERRQ(ierr);
10189     if (coneSize != 2) SETERRQ3(comm, PETSC_ERR_ARG_OUTOFRANGE, "Edge %d matching subedge %d had cone size %d != 2", edge, subedge, coneSize);
10190     ierr = DMPlexGetCone(subdm, e, &cone);CHKERRQ(ierr);
10191     for(c = 0; c < coneSize; ++c) {
10192       ierr = PetscFindInt(cone[c], numSubVertices, subVertices, &subv);CHKERRQ(ierr);
10193       if (subv < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Vertex %d has no matching subvertex", cone[v]);
10194       coneNew[c] = firstSubVertex + subv;
10195     }
10196     ierr = DMPlexSetCone(subdm, e, coneNew);CHKERRQ(ierr);
10197   }
10198   for (f = 0; f < numSubFaces; ++f) {
10199     const PetscInt  face    = subFaces[f];
10200     const PetscInt  subface = firstSubFace + f;
10201     const PetscInt *cone, *support;
10202     PetscInt        coneSize, supportSize, subvertex, subcell, c, s;
10203 
10204     ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10205     ierr = DMPlexGetCone(dm, face, &cone);CHKERRQ(ierr);
10206     for(c = 0; c < coneSize; ++c) {
10207       ierr = PetscFindInt(cone[c], numSubVertices, subVertices, &subvertex);CHKERRQ(ierr);
10208       if (subvertex < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Vertex %d has no matching subvertex", cone[v]);
10209       coneNew[c] = firstSubVertex + subvertex;
10210     }
10211     ierr = DMPlexSetCone(subdm, subface, coneNew);CHKERRQ(ierr);
10212     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10213     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10214     for(s = 0; s < supportSize; ++s) {
10215       ierr = PetscFindInt(support[s], numSubCells, subCells, &subcell);CHKERRQ(ierr);
10216       if (subcell < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Subcell %d not found in surface label", support[s]);
10217       /* ierr = DMPlexAddCone(subdm, subcell, 1);CHKERRQ(ierr); */
10218     }
10219   }
10220   ierr = ISRestoreIndices(subcellIS, &subCells);CHKERRQ(ierr);
10221   ierr = ISDestroy(&subcellIS);CHKERRQ(ierr);
10222   ierr = ISRestoreIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10223   ierr = ISDestroy(&subvertexIS);CHKERRQ(ierr);
10224   if (dim > 1) {
10225     ierr = ISRestoreIndices(subfaceIS, &subFaces);CHKERRQ(ierr);
10226     ierr = ISDestroy(&subfaceIS);CHKERRQ(ierr);
10227   }
10228   if (dim > 2) {
10229     ierr = ISRestoreIndices(subedgeIS, &subEdges);CHKERRQ(ierr);
10230     ierr = ISDestroy(&subedgeIS);CHKERRQ(ierr);
10231   }
10232   ierr = DMPlexSymmetrize(subdm);CHKERRQ(ierr);
10233   ierr = DMPlexStratify(subdm);CHKERRQ(ierr);
10234   /* Build coordinates */
10235   {
10236     PetscSection    coordSection, subCoordSection;
10237     Vec             coordinates, subCoordinates;
10238     PetscScalar    *coords, *subCoords;
10239     PetscInt        coordSize;
10240 
10241     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10242     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10243     ierr = DMPlexGetCoordinateSection(subdm, &subCoordSection);CHKERRQ(ierr);
10244     ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVertices);CHKERRQ(ierr);
10245     for (v = 0; v < numSubVertices; ++v) {
10246       const PetscInt vertex    = subVertices[v];
10247       const PetscInt subVertex = firstSubVertex+v;
10248       PetscInt       dof;
10249 
10250       ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10251       ierr = PetscSectionSetDof(subCoordSection, subVertex, dof);CHKERRQ(ierr);
10252     }
10253     ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10254     ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10255     ierr = VecCreate(comm, &subCoordinates);CHKERRQ(ierr);
10256     ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10257     ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10258     ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10259     ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10260     for (v = 0; v < numSubVertices; ++v) {
10261       const PetscInt vertex    = subVertices[v];
10262       const PetscInt subVertex = firstSubVertex+v;
10263       PetscInt dof, off, sdof, soff, d;
10264 
10265       ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10266       ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10267       ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10268       ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10269       if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10270       for (d = 0; d < dof; ++d) {
10271         subCoords[soff+d] = coords[off+d];
10272       }
10273     }
10274     ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10275     ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10276     ierr = DMSetCoordinatesLocal(subdm, subCoordinates);CHKERRQ(ierr);
10277     ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10278   }
10279   /* TODO: Create map from submesh points to original mesh points */
10280   ierr = DMPlexSetSubpointMap(subdm, subpointMap);CHKERRQ(ierr);
10281   PetscFunctionReturn(0);
10282 }
10283 
10284 #undef __FUNCT__
10285 #define __FUNCT__ "DMPlexCreateSubmesh"
10286 /*
10287   DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label
10288 
10289   Input Parameters:
10290 + dm           - The original mesh
10291 . vertexLabel  - The DMLabel marking vertices contained in the surface
10292 - surfaceLabel - If not PETSC_NULL, create a new label with all the surface points labeled by dimension
10293 
10294   Output Parameter:
10295 . subdm - The surface mesh
10296 
10297   Level: developer
10298 
10299 .seealso: DMPlexGetLabel(), DMLabelSetValue()
10300 */
10301 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char vertexLabel[], const char surfaceLabel[], DM *subdm)
10302 {
10303   PetscInt       dim, depth;
10304   PetscErrorCode ierr;
10305 
10306   PetscFunctionBegin;
10307   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10308   PetscValidCharPointer(vertexLabel, 2);
10309   PetscValidPointer(subdm, 4);
10310   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10311   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10312   ierr = DMCreate(((PetscObject) dm)->comm, subdm);CHKERRQ(ierr);
10313   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10314   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10315   if (depth == dim) {
10316     ierr = DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, surfaceLabel, *subdm);CHKERRQ(ierr);
10317   } else {
10318     ierr = DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, surfaceLabel, *subdm);CHKERRQ(ierr);
10319   }
10320   PetscFunctionReturn(0);
10321 }
10322 
10323 #undef __FUNCT__
10324 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10325 /* We can easily have a form that takes an IS instead */
10326 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10327 {
10328   PetscSection   section, globalSection;
10329   PetscInt      *numbers, p;
10330   PetscErrorCode ierr;
10331 
10332   PetscFunctionBegin;
10333   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10334   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10335   for (p = pStart; p < pEnd; ++p) {
10336     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10337   }
10338   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10339   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10340   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10341   for (p = pStart; p < pEnd; ++p) {
10342     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10343   }
10344   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10345   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10346   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10347   PetscFunctionReturn(0);
10348 }
10349 
10350 #undef __FUNCT__
10351 #define __FUNCT__ "DMPlexGetCellNumbering"
10352 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10353 {
10354   DM_Plex       *mesh = (DM_Plex*) dm->data;
10355   PetscInt       cellHeight, cStart, cEnd, cMax;
10356   PetscErrorCode ierr;
10357 
10358   PetscFunctionBegin;
10359   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10360   if (!mesh->globalCellNumbers) {
10361     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10362     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10363     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10364     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
10365     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10366   }
10367   *globalCellNumbers = mesh->globalCellNumbers;
10368   PetscFunctionReturn(0);
10369 }
10370 
10371 #undef __FUNCT__
10372 #define __FUNCT__ "DMPlexGetVertexNumbering"
10373 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10374 {
10375   DM_Plex       *mesh = (DM_Plex*) dm->data;
10376   PetscInt       vStart, vEnd, vMax;
10377   PetscErrorCode ierr;
10378 
10379   PetscFunctionBegin;
10380   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10381   if (!mesh->globalVertexNumbers) {
10382     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10383     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10384     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
10385     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10386   }
10387   *globalVertexNumbers = mesh->globalVertexNumbers;
10388   PetscFunctionReturn(0);
10389 }
10390 
10391 #undef __FUNCT__
10392 #define __FUNCT__ "DMPlexGetSubpointMap"
10393 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10394 {
10395   DM_Plex *mesh = (DM_Plex*) dm->data;
10396 
10397   PetscFunctionBegin;
10398   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10399   PetscValidPointer(subpointMap, 2);
10400   *subpointMap = mesh->subpointMap;
10401   PetscFunctionReturn(0);
10402 }
10403 
10404 #undef __FUNCT__
10405 #define __FUNCT__ "DMPlexSetSubpointMap"
10406 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10407 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10408 {
10409   DM_Plex       *mesh = (DM_Plex *) dm->data;
10410   PetscErrorCode ierr;
10411 
10412   PetscFunctionBegin;
10413   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10414   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10415   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
10416   mesh->subpointMap = subpointMap;
10417   ierr = PetscObjectReference((PetscObject) mesh->subpointMap);CHKERRQ(ierr);
10418   PetscFunctionReturn(0);
10419 }
10420 
10421 #undef __FUNCT__
10422 #define __FUNCT__ "DMPlexGetScale"
10423 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10424 {
10425   DM_Plex *mesh = (DM_Plex*) dm->data;
10426 
10427   PetscFunctionBegin;
10428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10429   PetscValidPointer(scale, 3);
10430   *scale = mesh->scale[unit];
10431   PetscFunctionReturn(0);
10432 }
10433 
10434 #undef __FUNCT__
10435 #define __FUNCT__ "DMPlexSetScale"
10436 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10437 {
10438   DM_Plex *mesh = (DM_Plex*) dm->data;
10439 
10440   PetscFunctionBegin;
10441   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10442   mesh->scale[unit] = scale;
10443   PetscFunctionReturn(0);
10444 }
10445 
10446 
10447 /*******************************************************************************
10448 This should be in a separate Discretization object, but I am not sure how to lay
10449 it out yet, so I am stuffing things here while I experiment.
10450 *******************************************************************************/
10451 #undef __FUNCT__
10452 #define __FUNCT__ "DMPlexSetFEMIntegration"
10453 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10454                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10455                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10456                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10457                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10458                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10459                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10460                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10461                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10462                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10463                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10464                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10465                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10466                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10467                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10468                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10469                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10470 {
10471   DM_Plex *mesh = (DM_Plex*) dm->data;
10472 
10473   PetscFunctionBegin;
10474   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10475   mesh->integrateResidualFEM       = integrateResidualFEM;
10476   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10477   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10478   PetscFunctionReturn(0);
10479 }
10480 
10481 #undef __FUNCT__
10482 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10483 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10484 {
10485   Vec            coordinates;
10486   PetscSection   section, cSection;
10487   PetscInt       dim, vStart, vEnd, v, c, d;
10488   PetscScalar   *values, *cArray;
10489   PetscReal     *coords;
10490   PetscErrorCode ierr;
10491 
10492   PetscFunctionBegin;
10493   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10494   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10495   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10496   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10497   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10498   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10499   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10500   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10501   for (v = vStart; v < vEnd; ++v) {
10502     PetscInt dof, off;
10503 
10504     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10505     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10506     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10507     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
10508     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10509     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10510   }
10511   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10512   /* Temporary, must be replaced by a projection on the finite element basis */
10513   {
10514     PetscInt eStart = 0, eEnd = 0, e, depth;
10515 
10516     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10517     --depth;
10518     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10519     for (e = eStart; e < eEnd; ++e) {
10520       const PetscInt *cone = PETSC_NULL;
10521       PetscInt        coneSize, d;
10522       PetscScalar    *coordsA, *coordsB;
10523 
10524       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10525       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10526       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10527       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10528       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10529       for (d = 0; d < dim; ++d) {
10530         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10531       }
10532       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10533       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10534     }
10535   }
10536 
10537   ierr = PetscFree(coords);CHKERRQ(ierr);
10538   ierr = PetscFree(values);CHKERRQ(ierr);
10539 #if 0
10540   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10541   PetscReal      detJ;
10542 
10543   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10544   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10545   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10546 
10547   for (PetscInt c = cStart; c < cEnd; ++c) {
10548     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10549     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10550     const int                          oSize   = pV.getSize();
10551     int                                v       = 0;
10552 
10553     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10554     for (PetscInt cl = 0; cl < oSize; ++cl) {
10555       const PetscInt fDim;
10556 
10557       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10558       if (pointDim) {
10559         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10560           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10561         }
10562       }
10563     }
10564     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10565     pV.clear();
10566   }
10567   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10568   ierr = PetscFree(values);CHKERRQ(ierr);
10569 #endif
10570   PetscFunctionReturn(0);
10571 }
10572 
10573 #undef __FUNCT__
10574 #define __FUNCT__ "DMPlexProjectFunction"
10575 /*@C
10576   DMPlexProjectFunction - This projects the given function into the function space provided.
10577 
10578   Input Parameters:
10579 + dm      - The DM
10580 . numComp - The number of components (functions)
10581 . funcs   - The coordinate functions to evaluate
10582 - mode    - The insertion mode for values
10583 
10584   Output Parameter:
10585 . X - vector
10586 
10587   Level: developer
10588 
10589   Note:
10590   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10591   We will eventually fix it.
10592 
10593 ,seealso: DMPlexComputeL2Diff()
10594 */
10595 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10596 {
10597   Vec            localX;
10598   PetscErrorCode ierr;
10599 
10600   PetscFunctionBegin;
10601   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10602   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10603   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10604   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10605   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10606   PetscFunctionReturn(0);
10607 }
10608 
10609 #undef __FUNCT__
10610 #define __FUNCT__ "DMPlexComputeL2Diff"
10611 /*@C
10612   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10613 
10614   Input Parameters:
10615 + dm    - The DM
10616 . quad  - The PetscQuadrature object for each field
10617 . funcs - The functions to evaluate for each field component
10618 - X     - The coefficient vector u_h
10619 
10620   Output Parameter:
10621 . diff - The diff ||u - u_h||_2
10622 
10623   Level: developer
10624 
10625 .seealso: DMPlexProjectFunction()
10626 */
10627 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10628 {
10629   const PetscInt debug = 0;
10630   PetscSection   section;
10631   Vec            localX;
10632   PetscReal     *coords, *v0, *J, *invJ, detJ;
10633   PetscReal      localDiff = 0.0;
10634   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10635   PetscErrorCode ierr;
10636 
10637   PetscFunctionBegin;
10638   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10639   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10640   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10641   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10642   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10643   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10644   for (field = 0; field < numFields; ++field) {
10645     numComponents += quad[field].numComponents;
10646   }
10647   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10648   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10649   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10650   for (c = cStart; c < cEnd; ++c) {
10651     const PetscScalar *x;
10652     PetscReal          elemDiff = 0.0;
10653 
10654     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10655     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10656     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10657 
10658     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10659       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10660       const PetscReal *quadPoints    = quad[field].quadPoints;
10661       const PetscReal *quadWeights   = quad[field].quadWeights;
10662       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10663       const PetscInt   numBasisComps = quad[field].numComponents;
10664       const PetscReal *basis         = quad[field].basis;
10665       PetscInt         q, d, e, fc, f;
10666 
10667       if (debug) {
10668         char title[1024];
10669         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10670         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10671       }
10672       for (q = 0; q < numQuadPoints; ++q) {
10673         for (d = 0; d < dim; d++) {
10674           coords[d] = v0[d];
10675           for (e = 0; e < dim; e++) {
10676             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10677           }
10678         }
10679         for (fc = 0; fc < numBasisComps; ++fc) {
10680           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10681           PetscReal       interpolant = 0.0;
10682           for (f = 0; f < numBasisFuncs; ++f) {
10683             const PetscInt fidx = f*numBasisComps+fc;
10684             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10685           }
10686           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10687           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10688         }
10689       }
10690       comp        += numBasisComps;
10691       fieldOffset += numBasisFuncs*numBasisComps;
10692     }
10693     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10694     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10695     localDiff += elemDiff;
10696   }
10697   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10698   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10699   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10700   *diff = PetscSqrtReal(*diff);
10701   PetscFunctionReturn(0);
10702 }
10703 
10704 #undef __FUNCT__
10705 #define __FUNCT__ "DMPlexComputeResidualFEM"
10706 /*@
10707   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10708 
10709   Input Parameters:
10710 + dm - The mesh
10711 . X  - Local input vector
10712 - user - The user context
10713 
10714   Output Parameter:
10715 . F  - Local output vector
10716 
10717   Note:
10718   The second member of the user context must be an FEMContext.
10719 
10720   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10721   like a GPU, or vectorize on a multicore machine.
10722 
10723 .seealso: DMPlexComputeJacobianActionFEM()
10724 */
10725 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10726 {
10727   DM_Plex         *mesh = (DM_Plex*) dm->data;
10728   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10729   PetscQuadrature *quad = fem->quad;
10730   PetscSection     section;
10731   PetscReal       *v0, *J, *invJ, *detJ;
10732   PetscScalar     *elemVec, *u;
10733   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10734   PetscInt         cellDof = 0, numComponents = 0;
10735   PetscErrorCode   ierr;
10736 
10737   PetscFunctionBegin;
10738   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10739   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10740   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10741   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10742   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10743   numCells = cEnd - cStart;
10744   for (field = 0; field < numFields; ++field) {
10745     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10746     numComponents += quad[field].numComponents;
10747   }
10748   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10749   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10750   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);
10751   for (c = cStart; c < cEnd; ++c) {
10752     const PetscScalar *x;
10753     PetscInt           i;
10754 
10755     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10756     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10757     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10758 
10759     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10760     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10761   }
10762   for (field = 0; field < numFields; ++field) {
10763     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10764     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10765     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10766     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10767     /* Conforming batches */
10768     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10769     PetscInt numBlocks  = 1;
10770     PetscInt batchSize  = numBlocks * blockSize;
10771     PetscInt numBatches = numBatchesTmp;
10772     PetscInt numChunks  = numCells / (numBatches*batchSize);
10773     /* Remainder */
10774     PetscInt numRemainder = numCells % (numBatches * batchSize);
10775     PetscInt offset       = numCells - numRemainder;
10776 
10777     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10778     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10779                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10780   }
10781   for (c = cStart; c < cEnd; ++c) {
10782     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10783     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10784   }
10785   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10786   if (mesh->printFEM) {
10787     PetscMPIInt rank, numProcs;
10788     PetscInt    p;
10789 
10790     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10791     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10792     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10793     for (p = 0; p < numProcs; ++p) {
10794       if (p == rank) {
10795         Vec f;
10796 
10797         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10798         ierr = VecCopy(F, f);CHKERRQ(ierr);
10799         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10800         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10801         ierr = VecDestroy(&f);CHKERRQ(ierr);
10802         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10803       }
10804       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10805     }
10806   }
10807   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10808   PetscFunctionReturn(0);
10809 }
10810 
10811 #undef __FUNCT__
10812 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10813 /*@C
10814   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10815 
10816   Input Parameters:
10817 + dm - The mesh
10818 . J  - The Jacobian shell matrix
10819 . X  - Local input vector
10820 - user - The user context
10821 
10822   Output Parameter:
10823 . F  - Local output vector
10824 
10825   Note:
10826   The second member of the user context must be an FEMContext.
10827 
10828   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10829   like a GPU, or vectorize on a multicore machine.
10830 
10831 .seealso: DMPlexComputeResidualFEM()
10832 */
10833 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10834 {
10835   DM_Plex         *mesh = (DM_Plex*) dm->data;
10836   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10837   PetscQuadrature *quad = fem->quad;
10838   PetscSection     section;
10839   JacActionCtx    *jctx;
10840   PetscReal       *v0, *J, *invJ, *detJ;
10841   PetscScalar     *elemVec, *u, *a;
10842   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10843   PetscInt         cellDof = 0;
10844   PetscErrorCode   ierr;
10845 
10846   PetscFunctionBegin;
10847   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10848   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10849   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10850   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10851   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10852   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10853   numCells = cEnd - cStart;
10854   for (field = 0; field < numFields; ++field) {
10855     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10856   }
10857   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10858   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);
10859   for (c = cStart; c < cEnd; ++c) {
10860     const PetscScalar *x;
10861     PetscInt           i;
10862 
10863     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10864     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10865     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10866     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10867     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10868     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10869     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
10870     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10871   }
10872   for (field = 0; field < numFields; ++field) {
10873     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10874     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10875     /* Conforming batches */
10876     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10877     PetscInt numBlocks  = 1;
10878     PetscInt batchSize  = numBlocks * blockSize;
10879     PetscInt numBatches = numBatchesTmp;
10880     PetscInt numChunks  = numCells / (numBatches*batchSize);
10881     /* Remainder */
10882     PetscInt numRemainder = numCells % (numBatches * batchSize);
10883     PetscInt offset       = numCells - numRemainder;
10884 
10885     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);
10886     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],
10887                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10888   }
10889   for (c = cStart; c < cEnd; ++c) {
10890     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10891     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10892   }
10893   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10894   if (mesh->printFEM) {
10895     PetscMPIInt rank, numProcs;
10896     PetscInt    p;
10897 
10898     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10899     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10900     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10901     for (p = 0; p < numProcs; ++p) {
10902       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10903       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10904     }
10905   }
10906   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10907   PetscFunctionReturn(0);
10908 }
10909 
10910 #undef __FUNCT__
10911 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10912 /*@
10913   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10914 
10915   Input Parameters:
10916 + dm - The mesh
10917 . X  - Local input vector
10918 - user - The user context
10919 
10920   Output Parameter:
10921 . Jac  - Jacobian matrix
10922 
10923   Note:
10924   The second member of the user context must be an FEMContext.
10925 
10926   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10927   like a GPU, or vectorize on a multicore machine.
10928 
10929 .seealso: FormFunctionLocal()
10930 */
10931 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10932 {
10933   DM_Plex         *mesh = (DM_Plex*) dm->data;
10934   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10935   PetscQuadrature *quad = fem->quad;
10936   PetscSection     section;
10937   PetscReal       *v0, *J, *invJ, *detJ;
10938   PetscScalar     *elemMat, *u;
10939   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10940   PetscInt         cellDof = 0, numComponents = 0;
10941   PetscBool        isShell;
10942   PetscErrorCode   ierr;
10943 
10944   PetscFunctionBegin;
10945   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10946   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10947   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10948   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10949   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10950   numCells = cEnd - cStart;
10951   for (field = 0; field < numFields; ++field) {
10952     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10953     numComponents += quad[field].numComponents;
10954   }
10955   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10956   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10957   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);
10958   for (c = cStart; c < cEnd; ++c) {
10959     const PetscScalar *x;
10960     PetscInt           i;
10961 
10962     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10963     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10964     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10965 
10966     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10967     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10968   }
10969   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10970   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10971     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10972     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10973     PetscInt       fieldJ;
10974 
10975     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10976       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10977       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10978       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10979       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10980       /* Conforming batches */
10981       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10982       PetscInt numBlocks  = 1;
10983       PetscInt batchSize  = numBlocks * blockSize;
10984       PetscInt numBatches = numBatchesTmp;
10985       PetscInt numChunks  = numCells / (numBatches*batchSize);
10986       /* Remainder */
10987       PetscInt numRemainder = numCells % (numBatches * batchSize);
10988       PetscInt offset       = numCells - numRemainder;
10989 
10990       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10991       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10992                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10993     }
10994   }
10995   for (c = cStart; c < cEnd; ++c) {
10996     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10997     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10998   }
10999   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
11000 
11001   /* Assemble matrix, using the 2-step process:
11002        MatAssemblyBegin(), MatAssemblyEnd(). */
11003   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11004   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11005 
11006   if (mesh->printFEM) {
11007     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
11008     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
11009     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
11010   }
11011   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11012   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
11013   if (isShell) {
11014     JacActionCtx *jctx;
11015 
11016     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
11017     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
11018   }
11019   *str = SAME_NONZERO_PATTERN;
11020   PetscFunctionReturn(0);
11021 }
11022 
11023 
11024 #undef __FUNCT__
11025 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
11026 /*@C
11027   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
11028   the local section and an SF describing the section point overlap.
11029 
11030   Input Parameters:
11031   + s - The PetscSection for the local field layout
11032   . sf - The SF describing parallel layout of the section points
11033   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
11034   . label - The label specifying the points
11035   - labelValue - The label stratum specifying the points
11036 
11037   Output Parameter:
11038   . gsection - The PetscSection for the global field layout
11039 
11040   Note: This gives negative sizes and offsets to points not owned by this process
11041 
11042   Level: developer
11043 
11044 .seealso: PetscSectionCreate()
11045 @*/
11046 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
11047 {
11048   PetscInt      *neg;
11049   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
11050   PetscErrorCode ierr;
11051 
11052   PetscFunctionBegin;
11053   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
11054   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
11055   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
11056   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
11057   /* Mark ghost points with negative dof */
11058   for (p = pStart; p < pEnd; ++p) {
11059     PetscInt value;
11060 
11061     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11062     if (value != labelValue) continue;
11063     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11064     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11065     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11066     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11067     neg[p-pStart] = -(dof+1);
11068   }
11069   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11070   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11071   if (nroots >= 0) {
11072     if (nroots > pEnd - pStart) {
11073       PetscInt *tmpDof;
11074       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11075       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11076       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11077       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11078       for (p = pStart; p < pEnd; ++p) {
11079         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
11080       }
11081       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11082     } else {
11083       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11084       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11085     }
11086   }
11087   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11088   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11089     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11090 
11091     (*gsection)->atlasOff[p] = off;
11092 
11093     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11094   }
11095   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11096   globalOff -= off;
11097   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11098     (*gsection)->atlasOff[p] += globalOff;
11099 
11100     neg[p] = -((*gsection)->atlasOff[p]+1);
11101   }
11102   /* Put in negative offsets for ghost points */
11103   if (nroots >= 0) {
11104     if (nroots > pEnd - pStart) {
11105       PetscInt *tmpOff;
11106       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11107       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11108       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11109       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11110       for (p = pStart; p < pEnd; ++p) {
11111         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
11112       }
11113       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11114     } else {
11115       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11116       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11117     }
11118   }
11119   ierr = PetscFree(neg);CHKERRQ(ierr);
11120   PetscFunctionReturn(0);
11121 }
11122