xref: /petsc/src/dm/impls/plex/plex.c (revision b6bfaf9a0a178e626c17e7b8aafd5e3bedcd9a6d)
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   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
513   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
514   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
515 
516   /*
517    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
518     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
519        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
520     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
521        Create sfAdj connecting rootSectionAdj and leafSectionAdj
522     3. Visit unowned points on interface, write adjacencies to adj
523        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
524     4. Visit owned points on interface, write adjacencies to rootAdj
525        Remove redundancy in rootAdj
526    ** The last two traversals use transitive closure
527     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
528        Allocate memory addressed by sectionAdj (cols)
529     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
530    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
531   */
532 
533   for (l = 0; l < nleaves; ++l) {
534     PetscInt dof, off, d, q;
535     PetscInt p = leaves[l], numAdj = maxAdjSize;
536 
537     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
538     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
539     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
540     for (q = 0; q < numAdj; ++q) {
541       PetscInt ndof, ncdof;
542 
543       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
544       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
545       for (d = off; d < off+dof; ++d) {
546         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
547       }
548     }
549   }
550   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
551   if (debug) {
552     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
553     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
554   }
555   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
556   if (size > 1) {
557     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
558     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
559   }
560   if (debug) {
561     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
562     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
563   }
564   /* Add in local adjacency sizes for owned dofs on interface (roots) */
565   for (p = pStart; p < pEnd; ++p) {
566     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
567 
568     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
569     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
570     if (!dof) continue;
571     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
572     if (adof <= 0) continue;
573     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
574     for (q = 0; q < numAdj; ++q) {
575       PetscInt ndof, ncdof;
576 
577       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
578       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
579       for (d = off; d < off+dof; ++d) {
580         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
581       }
582     }
583   }
584   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
585   if (debug) {
586     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
587     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
588   }
589   /* Create adj SF based on dof SF */
590   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
591   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
592   if (debug) {
593     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
594     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
595   }
596   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
597   /* Create leaf adjacency */
598   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
599   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
600   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
601   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
602   for (l = 0; l < nleaves; ++l) {
603     PetscInt dof, off, d, q;
604     PetscInt p = leaves[l], numAdj = maxAdjSize;
605 
606     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
607     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
608     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
609     for (d = off; d < off+dof; ++d) {
610       PetscInt aoff, i = 0;
611 
612       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
613       for (q = 0; q < numAdj; ++q) {
614         PetscInt  ndof, ncdof, ngoff, nd;
615 
616         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
617         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
618         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
619         for (nd = 0; nd < ndof-ncdof; ++nd) {
620           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
621           ++i;
622         }
623       }
624     }
625   }
626   /* Debugging */
627   if (debug) {
628     IS tmp;
629     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
630     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
631     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
632   }
633   /* Gather adjacenct indices to root */
634   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
635   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
636   for (r = 0; r < adjSize; ++r) {
637     rootAdj[r] = -1;
638   }
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   PetscErrorCode ierr;
898   PetscInt c,cStart,cEnd,pStart,pEnd;
899   PetscInt *tmpClosure,*tmpAdj,*visits;
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   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
906   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
907   npoints = pEnd - pStart;
908   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
909   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
910   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
911   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
912   for (c=cStart; c<cEnd; c++) {
913     PetscInt *support = tmpClosure;
914     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
915     for (p=0; p<supportSize; p++) {
916       lvisits[support[p]]++;
917     }
918   }
919   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
920   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
921   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
922   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
923 
924   ierr = PetscSFGetRanks();CHKERRQ(ierr);
925 
926 
927   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
928   for (c=cStart; c<cEnd; c++) {
929     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
930     /*
931      Depth-first walk of transitive closure.
932      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.
933      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
934      */
935   }
936 
937   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
938   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
939   PetscFunctionReturn(0);
940 }
941 #endif
942 
943 #undef __FUNCT__
944 #define __FUNCT__ "DMCreateMatrix_Plex"
945 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
946 {
947   PetscSection   section, sectionGlobal;
948   PetscInt       bs = -1;
949   PetscInt       localSize;
950   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
951   PetscErrorCode ierr;
952 
953   PetscFunctionBegin;
954 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
955   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
956 #endif
957   if (!mtype) mtype = MATAIJ;
958   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
959   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
960   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
961   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
962   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
963   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
964   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
965   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
966   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
967   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
973   /* Check for symmetric storage */
974   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
975   if (isSymmetric) {
976     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
977   }
978   if (!isShell) {
979     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
980     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal;
981 
982     if (bs < 0) {
983       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
984         PetscInt pStart, pEnd, p, dof;
985 
986         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
987         for (p = pStart; p < pEnd; ++p) {
988           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
989           if (dof) {
990             bs = dof;
991             break;
992           }
993         }
994       } else {
995         bs = 1;
996       }
997       /* Must have same blocksize on all procs (some might have no points) */
998       bsLocal = bs;
999       ierr = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1000     }
1001     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1002     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1003     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1004     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1005     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1006     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1007     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1008   }
1009   PetscFunctionReturn(0);
1010 }
1011 
1012 #undef __FUNCT__
1013 #define __FUNCT__ "DMPlexGetDimension"
1014 /*@
1015   DMPlexGetDimension - Return the topological mesh dimension
1016 
1017   Not collective
1018 
1019   Input Parameter:
1020 . mesh - The DMPlex
1021 
1022   Output Parameter:
1023 . dim - The topological mesh dimension
1024 
1025   Level: beginner
1026 
1027 .seealso: DMPlexCreate()
1028 @*/
1029 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1030 {
1031   DM_Plex *mesh = (DM_Plex *) dm->data;
1032 
1033   PetscFunctionBegin;
1034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1035   PetscValidPointer(dim, 2);
1036   *dim = mesh->dim;
1037   PetscFunctionReturn(0);
1038 }
1039 
1040 #undef __FUNCT__
1041 #define __FUNCT__ "DMPlexSetDimension"
1042 /*@
1043   DMPlexSetDimension - Set the topological mesh dimension
1044 
1045   Collective on mesh
1046 
1047   Input Parameters:
1048 + mesh - The DMPlex
1049 - dim - The topological mesh dimension
1050 
1051   Level: beginner
1052 
1053 .seealso: DMPlexCreate()
1054 @*/
1055 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1056 {
1057   DM_Plex *mesh = (DM_Plex *) dm->data;
1058 
1059   PetscFunctionBegin;
1060   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1061   PetscValidLogicalCollectiveInt(dm, dim, 2);
1062   mesh->dim = dim;
1063   mesh->preallocCenterDim = dim;
1064   PetscFunctionReturn(0);
1065 }
1066 
1067 #undef __FUNCT__
1068 #define __FUNCT__ "DMPlexGetChart"
1069 /*@
1070   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1071 
1072   Not collective
1073 
1074   Input Parameter:
1075 . mesh - The DMPlex
1076 
1077   Output Parameters:
1078 + pStart - The first mesh point
1079 - pEnd   - The upper bound for mesh points
1080 
1081   Level: beginner
1082 
1083 .seealso: DMPlexCreate(), DMPlexSetChart()
1084 @*/
1085 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1086 {
1087   DM_Plex    *mesh = (DM_Plex *) dm->data;
1088   PetscErrorCode ierr;
1089 
1090   PetscFunctionBegin;
1091   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1092   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1093   PetscFunctionReturn(0);
1094 }
1095 
1096 #undef __FUNCT__
1097 #define __FUNCT__ "DMPlexSetChart"
1098 /*@
1099   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1100 
1101   Not collective
1102 
1103   Input Parameters:
1104 + mesh - The DMPlex
1105 . pStart - The first mesh point
1106 - pEnd   - The upper bound for mesh points
1107 
1108   Output Parameters:
1109 
1110   Level: beginner
1111 
1112 .seealso: DMPlexCreate(), DMPlexGetChart()
1113 @*/
1114 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1115 {
1116   DM_Plex    *mesh = (DM_Plex *) dm->data;
1117   PetscErrorCode ierr;
1118 
1119   PetscFunctionBegin;
1120   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1121   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1122   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1123   PetscFunctionReturn(0);
1124 }
1125 
1126 #undef __FUNCT__
1127 #define __FUNCT__ "DMPlexGetConeSize"
1128 /*@
1129   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1130 
1131   Not collective
1132 
1133   Input Parameters:
1134 + mesh - The DMPlex
1135 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1136 
1137   Output Parameter:
1138 . size - The cone size for point p
1139 
1140   Level: beginner
1141 
1142 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1143 @*/
1144 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1145 {
1146   DM_Plex    *mesh = (DM_Plex *) dm->data;
1147   PetscErrorCode ierr;
1148 
1149   PetscFunctionBegin;
1150   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1151   PetscValidPointer(size, 3);
1152   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1153   PetscFunctionReturn(0);
1154 }
1155 
1156 #undef __FUNCT__
1157 #define __FUNCT__ "DMPlexSetConeSize"
1158 /*@
1159   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1160 
1161   Not collective
1162 
1163   Input Parameters:
1164 + mesh - The DMPlex
1165 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1166 - size - The cone size for point p
1167 
1168   Output Parameter:
1169 
1170   Note:
1171   This should be called after DMPlexSetChart().
1172 
1173   Level: beginner
1174 
1175 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1176 @*/
1177 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1178 {
1179   DM_Plex    *mesh = (DM_Plex *) dm->data;
1180   PetscErrorCode ierr;
1181 
1182   PetscFunctionBegin;
1183   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1184   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1185   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1186   PetscFunctionReturn(0);
1187 }
1188 
1189 #undef __FUNCT__
1190 #define __FUNCT__ "DMPlexGetCone"
1191 /*@C
1192   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1193 
1194   Not collective
1195 
1196   Input Parameters:
1197 + mesh - The DMPlex
1198 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1199 
1200   Output Parameter:
1201 . cone - An array of points which are on the in-edges for point p
1202 
1203   Level: beginner
1204 
1205   Note:
1206   This routine is not available in Fortran.
1207 
1208 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1209 @*/
1210 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1211 {
1212   DM_Plex    *mesh = (DM_Plex *) dm->data;
1213   PetscInt       off;
1214   PetscErrorCode ierr;
1215 
1216   PetscFunctionBegin;
1217   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1218   PetscValidPointer(cone, 3);
1219   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1220   *cone = &mesh->cones[off];
1221   PetscFunctionReturn(0);
1222 }
1223 
1224 #undef __FUNCT__
1225 #define __FUNCT__ "DMPlexSetCone"
1226 /*@
1227   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1228 
1229   Not collective
1230 
1231   Input Parameters:
1232 + mesh - The DMPlex
1233 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1234 - cone - An array of points which are on the in-edges for point p
1235 
1236   Output Parameter:
1237 
1238   Note:
1239   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1240 
1241   Level: beginner
1242 
1243 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1244 @*/
1245 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1246 {
1247   DM_Plex    *mesh = (DM_Plex *) dm->data;
1248   PetscInt       pStart, pEnd;
1249   PetscInt       dof, off, c;
1250   PetscErrorCode ierr;
1251 
1252   PetscFunctionBegin;
1253   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1254   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1255   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1256   if (dof) PetscValidPointer(cone, 3);
1257   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1258   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);
1259   for (c = 0; c < dof; ++c) {
1260     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);
1261     mesh->cones[off+c] = cone[c];
1262   }
1263   PetscFunctionReturn(0);
1264 }
1265 
1266 #undef __FUNCT__
1267 #define __FUNCT__ "DMPlexGetConeOrientation"
1268 /*@C
1269   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1270 
1271   Not collective
1272 
1273   Input Parameters:
1274 + mesh - The DMPlex
1275 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1276 
1277   Output Parameter:
1278 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1279                     integer giving the prescription for cone traversal. If it is negative, the cone is
1280                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1281                     the index of the cone point on which to start.
1282 
1283   Level: beginner
1284 
1285   Note:
1286   This routine is not available in Fortran.
1287 
1288 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1289 @*/
1290 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1291 {
1292   DM_Plex    *mesh = (DM_Plex *) dm->data;
1293   PetscInt       off;
1294   PetscErrorCode ierr;
1295 
1296   PetscFunctionBegin;
1297   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1298 #if defined(PETSC_USE_DEBUG)
1299   {
1300     PetscInt dof;
1301     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1302     if (dof) PetscValidPointer(coneOrientation, 3);
1303   }
1304 #endif
1305   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1306   *coneOrientation = &mesh->coneOrientations[off];
1307   PetscFunctionReturn(0);
1308 }
1309 
1310 #undef __FUNCT__
1311 #define __FUNCT__ "DMPlexSetConeOrientation"
1312 /*@
1313   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1314 
1315   Not collective
1316 
1317   Input Parameters:
1318 + mesh - The DMPlex
1319 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1320 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1321                     integer giving the prescription for cone traversal. If it is negative, the cone is
1322                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1323                     the index of the cone point on which to start.
1324 
1325   Output Parameter:
1326 
1327   Note:
1328   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1329 
1330   Level: beginner
1331 
1332 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1333 @*/
1334 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1335 {
1336   DM_Plex    *mesh = (DM_Plex *) dm->data;
1337   PetscInt       pStart, pEnd;
1338   PetscInt       dof, off, c;
1339   PetscErrorCode ierr;
1340 
1341   PetscFunctionBegin;
1342   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1343   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1344   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1345   if (dof) PetscValidPointer(coneOrientation, 3);
1346   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1347   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);
1348   for (c = 0; c < dof; ++c) {
1349     PetscInt cdof, o = coneOrientation[c];
1350 
1351     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1352     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);
1353     mesh->coneOrientations[off+c] = o;
1354   }
1355   PetscFunctionReturn(0);
1356 }
1357 
1358 #undef __FUNCT__
1359 #define __FUNCT__ "DMPlexInsertCone"
1360 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1361 {
1362   DM_Plex    *mesh = (DM_Plex *) dm->data;
1363   PetscInt       pStart, pEnd;
1364   PetscInt       dof, off;
1365   PetscErrorCode ierr;
1366 
1367   PetscFunctionBegin;
1368   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1369   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1370   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1371   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1372   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);
1373   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);
1374   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);
1375   mesh->cones[off+conePos] = conePoint;
1376   PetscFunctionReturn(0);
1377 }
1378 
1379 #undef __FUNCT__
1380 #define __FUNCT__ "DMPlexGetSupportSize"
1381 /*@
1382   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1383 
1384   Not collective
1385 
1386   Input Parameters:
1387 + mesh - The DMPlex
1388 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1389 
1390   Output Parameter:
1391 . size - The support size for point p
1392 
1393   Level: beginner
1394 
1395 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1396 @*/
1397 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1398 {
1399   DM_Plex    *mesh = (DM_Plex *) dm->data;
1400   PetscErrorCode ierr;
1401 
1402   PetscFunctionBegin;
1403   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1404   PetscValidPointer(size, 3);
1405   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1406   PetscFunctionReturn(0);
1407 }
1408 
1409 #undef __FUNCT__
1410 #define __FUNCT__ "DMPlexSetSupportSize"
1411 /*@
1412   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1413 
1414   Not collective
1415 
1416   Input Parameters:
1417 + mesh - The DMPlex
1418 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1419 - size - The support size for point p
1420 
1421   Output Parameter:
1422 
1423   Note:
1424   This should be called after DMPlexSetChart().
1425 
1426   Level: beginner
1427 
1428 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1429 @*/
1430 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1431 {
1432   DM_Plex    *mesh = (DM_Plex *) dm->data;
1433   PetscErrorCode ierr;
1434 
1435   PetscFunctionBegin;
1436   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1437   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1438   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1439   PetscFunctionReturn(0);
1440 }
1441 
1442 #undef __FUNCT__
1443 #define __FUNCT__ "DMPlexGetSupport"
1444 /*@C
1445   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1446 
1447   Not collective
1448 
1449   Input Parameters:
1450 + mesh - The DMPlex
1451 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1452 
1453   Output Parameter:
1454 . support - An array of points which are on the out-edges for point p
1455 
1456   Level: beginner
1457 
1458 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1459 @*/
1460 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1461 {
1462   DM_Plex    *mesh = (DM_Plex *) dm->data;
1463   PetscInt       off;
1464   PetscErrorCode ierr;
1465 
1466   PetscFunctionBegin;
1467   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1468   PetscValidPointer(support, 3);
1469   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1470   *support = &mesh->supports[off];
1471   PetscFunctionReturn(0);
1472 }
1473 
1474 #undef __FUNCT__
1475 #define __FUNCT__ "DMPlexSetSupport"
1476 /*@
1477   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1478 
1479   Not collective
1480 
1481   Input Parameters:
1482 + mesh - The DMPlex
1483 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1484 - support - An array of points which are on the in-edges for point p
1485 
1486   Output Parameter:
1487 
1488   Note:
1489   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1490 
1491   Level: beginner
1492 
1493 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1494 @*/
1495 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1496 {
1497   DM_Plex    *mesh = (DM_Plex *) dm->data;
1498   PetscInt       pStart, pEnd;
1499   PetscInt       dof, off, c;
1500   PetscErrorCode ierr;
1501 
1502   PetscFunctionBegin;
1503   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1504   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1505   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1506   if (dof) PetscValidPointer(support, 3);
1507   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1508   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);
1509   for (c = 0; c < dof; ++c) {
1510     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);
1511     mesh->supports[off+c] = support[c];
1512   }
1513   PetscFunctionReturn(0);
1514 }
1515 
1516 #undef __FUNCT__
1517 #define __FUNCT__ "DMPlexInsertSupport"
1518 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1519 {
1520   DM_Plex    *mesh = (DM_Plex *) dm->data;
1521   PetscInt       pStart, pEnd;
1522   PetscInt       dof, off;
1523   PetscErrorCode ierr;
1524 
1525   PetscFunctionBegin;
1526   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1527   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1528   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1529   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1530   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);
1531   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);
1532   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);
1533   mesh->supports[off+supportPos] = supportPoint;
1534   PetscFunctionReturn(0);
1535 }
1536 
1537 #undef __FUNCT__
1538 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1539 /*@C
1540   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1541 
1542   Not collective
1543 
1544   Input Parameters:
1545 + mesh - The DMPlex
1546 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1547 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1548 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1549 
1550   Output Parameters:
1551 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1552 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1553 
1554   Note:
1555   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1556 
1557   Level: beginner
1558 
1559 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1560 @*/
1561 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1562 {
1563   DM_Plex     *mesh = (DM_Plex *) dm->data;
1564   PetscInt       *closure, *fifo;
1565   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1566   PetscInt        tmpSize, t;
1567   PetscInt        depth = 0, maxSize;
1568   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1569   PetscErrorCode  ierr;
1570 
1571   PetscFunctionBegin;
1572   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1573   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1574   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1575   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1576   if (*points) {
1577     closure = *points;
1578   } else {
1579     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1580   }
1581   closure[0] = p; closure[1] = 0;
1582   /* This is only 1-level */
1583   if (useCone) {
1584     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1585     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1586     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1587   } else {
1588     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1589     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1590   }
1591   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1592     const PetscInt cp = tmp[t];
1593     const PetscInt co = tmpO ? tmpO[t] : 0;
1594 
1595     closure[closureSize]   = cp;
1596     closure[closureSize+1] = co;
1597     fifo[fifoSize]         = cp;
1598     fifo[fifoSize+1]       = co;
1599   }
1600   while (fifoSize - fifoStart) {
1601     const PetscInt q   = fifo[fifoStart];
1602     const PetscInt o   = fifo[fifoStart+1];
1603     const PetscInt rev = o >= 0 ? 0 : 1;
1604     const PetscInt off = rev ? -(o+1) : o;
1605 
1606     if (useCone) {
1607       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1608       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1609       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1610     } else {
1611       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1612       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1613       tmpO = PETSC_NULL;
1614     }
1615     for (t = 0; t < tmpSize; ++t) {
1616       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1617       const PetscInt cp = tmp[i];
1618       /* Must propogate orientation */
1619       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1620       PetscInt       c;
1621 
1622       /* Check for duplicate */
1623       for (c = 0; c < closureSize; c += 2) {
1624         if (closure[c] == cp) break;
1625       }
1626       if (c == closureSize) {
1627         closure[closureSize]   = cp;
1628         closure[closureSize+1] = co;
1629         fifo[fifoSize]         = cp;
1630         fifo[fifoSize+1]       = co;
1631         closureSize += 2;
1632         fifoSize    += 2;
1633       }
1634     }
1635     fifoStart += 2;
1636   }
1637   if (numPoints) *numPoints = closureSize/2;
1638   if (points)    *points    = closure;
1639   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1640   PetscFunctionReturn(0);
1641 }
1642 
1643 #undef __FUNCT__
1644 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1645 /*@C
1646   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1647 
1648   Not collective
1649 
1650   Input Parameters:
1651 + mesh - The DMPlex
1652 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1653 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1654 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1655 
1656   Output Parameters:
1657 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1658 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1659 
1660   Note:
1661   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1662 
1663   Level: beginner
1664 
1665 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1666 @*/
1667 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1668 {
1669   PetscErrorCode  ierr;
1670 
1671   PetscFunctionBegin;
1672   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1673   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1674   PetscFunctionReturn(0);
1675 }
1676 
1677 #undef __FUNCT__
1678 #define __FUNCT__ "DMPlexGetFaces"
1679 /*
1680   DMPlexGetFaces -
1681 
1682   Note: This will only work for cell-vertex meshes.
1683 */
1684 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1685 {
1686   DM_Plex     *mesh  = (DM_Plex *) dm->data;
1687   const PetscInt *cone  = PETSC_NULL;
1688   PetscInt        depth = 0, dim, coneSize;
1689   PetscErrorCode  ierr;
1690 
1691   PetscFunctionBegin;
1692   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1693   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1694   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1695   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1696   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1697   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1698   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1699   switch (dim) {
1700   case 2:
1701     switch (coneSize) {
1702     case 3:
1703       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1704       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1705       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1706       *numFaces = 3;
1707       *faceSize = 2;
1708       *faces    = mesh->facesTmp;
1709       break;
1710     case 4:
1711       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1712       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1713       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1714       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1715       *numFaces = 4;
1716       *faceSize = 2;
1717       *faces    = mesh->facesTmp;
1718       break;
1719     default:
1720       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1721     }
1722     break;
1723   case 3:
1724     switch (coneSize) {
1725     case 3:
1726       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1727       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1728       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1729       *numFaces = 3;
1730       *faceSize = 2;
1731       *faces    = mesh->facesTmp;
1732       break;
1733     case 4:
1734       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1735       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1736       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1737       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1738       *numFaces = 4;
1739       *faceSize = 3;
1740       *faces    = mesh->facesTmp;
1741       break;
1742     default:
1743       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1744     }
1745     break;
1746   default:
1747     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1748   }
1749   PetscFunctionReturn(0);
1750 }
1751 
1752 #undef __FUNCT__
1753 #define __FUNCT__ "DMPlexGetMaxSizes"
1754 /*@
1755   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1756 
1757   Not collective
1758 
1759   Input Parameter:
1760 . mesh - The DMPlex
1761 
1762   Output Parameters:
1763 + maxConeSize - The maximum number of in-edges
1764 - maxSupportSize - The maximum number of out-edges
1765 
1766   Level: beginner
1767 
1768 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1769 @*/
1770 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1771 {
1772   DM_Plex *mesh = (DM_Plex *) dm->data;
1773 
1774   PetscFunctionBegin;
1775   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1776   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1777   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1778   PetscFunctionReturn(0);
1779 }
1780 
1781 #undef __FUNCT__
1782 #define __FUNCT__ "DMSetUp_Plex"
1783 PetscErrorCode DMSetUp_Plex(DM dm)
1784 {
1785   DM_Plex    *mesh = (DM_Plex *) dm->data;
1786   PetscInt       size;
1787   PetscErrorCode ierr;
1788 
1789   PetscFunctionBegin;
1790   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1791   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1792   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1793   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1794   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1795   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1796   if (mesh->maxSupportSize) {
1797     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1798     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1799     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1800   }
1801   PetscFunctionReturn(0);
1802 }
1803 
1804 #undef __FUNCT__
1805 #define __FUNCT__ "DMCreateSubDM_Plex"
1806 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1807 {
1808   PetscSection   section, sectionGlobal;
1809   PetscInt      *subIndices;
1810   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1811   PetscErrorCode ierr;
1812 
1813   PetscFunctionBegin;
1814   if (!numFields) PetscFunctionReturn(0);
1815   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1816   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1817   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1818   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1819   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1820   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);
1821   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1822   for (p = pStart; p < pEnd; ++p) {
1823     PetscInt gdof;
1824 
1825     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1826     if (gdof > 0) {
1827       for (f = 0; f < numFields; ++f) {
1828         PetscInt fdof, fcdof;
1829 
1830         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1831         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1832         subSize += fdof-fcdof;
1833       }
1834     }
1835   }
1836   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1837   for (p = pStart; p < pEnd; ++p) {
1838     PetscInt gdof, goff;
1839 
1840     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1841     if (gdof > 0) {
1842       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1843       for (f = 0; f < numFields; ++f) {
1844         PetscInt fdof, fcdof, fc, f2, poff = 0;
1845 
1846         /* Can get rid of this loop by storing field information in the global section */
1847         for (f2 = 0; f2 < fields[f]; ++f2) {
1848           ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1849           ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1850           poff += fdof-fcdof;
1851         }
1852         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1853         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1854         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1855           subIndices[subOff] = goff+poff+fc;
1856         }
1857       }
1858     }
1859   }
1860   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1861   if (subdm) {
1862     PetscSection subsection;
1863     PetscBool    haveNull = PETSC_FALSE;
1864     PetscInt     f, nf = 0;
1865 
1866     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1867     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1868     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1869     for (f = 0; f < numFields; ++f) {
1870       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1871       if ((*subdm)->nullspaceConstructors[f]) {
1872         haveNull = PETSC_TRUE;
1873         nf       = f;
1874       }
1875     }
1876     if (haveNull) {
1877       MatNullSpace nullSpace;
1878 
1879       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1880       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1881       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1882     }
1883     if (dm->fields) {
1884       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);
1885       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1886       for (f = 0; f < numFields; ++f) {
1887         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1888       }
1889       if (numFields == 1) {
1890         MatNullSpace space;
1891         Mat          pmat;
1892 
1893         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject *) &space);CHKERRQ(ierr);
1894         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1895         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject *) &space);CHKERRQ(ierr);
1896         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1897         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject *) &pmat);CHKERRQ(ierr);
1898         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1899       }
1900     }
1901   }
1902   PetscFunctionReturn(0);
1903 }
1904 
1905 #undef __FUNCT__
1906 #define __FUNCT__ "DMPlexSymmetrize"
1907 /*@
1908   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1909 
1910   Not collective
1911 
1912   Input Parameter:
1913 . mesh - The DMPlex
1914 
1915   Output Parameter:
1916 
1917   Note:
1918   This should be called after all calls to DMPlexSetCone()
1919 
1920   Level: beginner
1921 
1922 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1923 @*/
1924 PetscErrorCode DMPlexSymmetrize(DM dm)
1925 {
1926   DM_Plex    *mesh = (DM_Plex *) dm->data;
1927   PetscInt      *offsets;
1928   PetscInt       supportSize;
1929   PetscInt       pStart, pEnd, p;
1930   PetscErrorCode ierr;
1931 
1932   PetscFunctionBegin;
1933   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1934   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1935   /* Calculate support sizes */
1936   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1937   for (p = pStart; p < pEnd; ++p) {
1938     PetscInt dof, off, c;
1939 
1940     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1941     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1942     for (c = off; c < off+dof; ++c) {
1943       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1944     }
1945   }
1946   for (p = pStart; p < pEnd; ++p) {
1947     PetscInt dof;
1948 
1949     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1950     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1951   }
1952   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1953   /* Calculate supports */
1954   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1955   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1956   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1957   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1958   for (p = pStart; p < pEnd; ++p) {
1959     PetscInt dof, off, c;
1960 
1961     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1962     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1963     for (c = off; c < off+dof; ++c) {
1964       const PetscInt q = mesh->cones[c];
1965       PetscInt       offS;
1966 
1967       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1968       mesh->supports[offS+offsets[q]] = p;
1969       ++offsets[q];
1970     }
1971   }
1972   ierr = PetscFree(offsets);CHKERRQ(ierr);
1973   PetscFunctionReturn(0);
1974 }
1975 
1976 #undef __FUNCT__
1977 #define __FUNCT__ "DMPlexSetDepth_Private"
1978 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1979 {
1980   PetscInt       d;
1981   PetscErrorCode ierr;
1982 
1983   PetscFunctionBegin;
1984   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1985   if (d < 0) {
1986     /* We are guaranteed that the point has a cone since the depth was not yet set */
1987     const PetscInt *cone = PETSC_NULL;
1988     PetscInt        dCone;
1989 
1990     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1991     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1992     d    = dCone+1;
1993     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1994   }
1995   *depth = d;
1996   PetscFunctionReturn(0);
1997 }
1998 
1999 #undef __FUNCT__
2000 #define __FUNCT__ "DMPlexStratify"
2001 /*@
2002   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2003   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2004   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2005   the DAG.
2006 
2007   Not collective
2008 
2009   Input Parameter:
2010 . mesh - The DMPlex
2011 
2012   Output Parameter:
2013 
2014   Notes:
2015   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2016   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2017 
2018   This should be called after all calls to DMPlexSymmetrize()
2019 
2020   Level: beginner
2021 
2022 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2023 @*/
2024 PetscErrorCode DMPlexStratify(DM dm)
2025 {
2026   DM_Plex    *mesh = (DM_Plex *) dm->data;
2027   PetscInt       pStart, pEnd, p;
2028   PetscInt       numRoots = 0, numLeaves = 0;
2029   PetscErrorCode ierr;
2030 
2031   PetscFunctionBegin;
2032   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2033   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2034   /* Calculate depth */
2035   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2036   /* Initialize roots and count leaves */
2037   for (p = pStart; p < pEnd; ++p) {
2038     PetscInt coneSize, supportSize;
2039 
2040     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2041     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2042     if (!coneSize && supportSize) {
2043       ++numRoots;
2044       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2045     } else if (!supportSize && coneSize) {
2046       ++numLeaves;
2047     } else if (!supportSize && !coneSize) {
2048       /* Isolated points */
2049       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2050     }
2051   }
2052   if (numRoots + numLeaves == (pEnd - pStart)) {
2053     for (p = pStart; p < pEnd; ++p) {
2054       PetscInt coneSize, supportSize;
2055 
2056       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2057       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2058       if (!supportSize && coneSize) {
2059         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2060       }
2061     }
2062   } else {
2063     /* This might be slow since lookup is not fast */
2064     for (p = pStart; p < pEnd; ++p) {
2065       PetscInt depth;
2066 
2067       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2068     }
2069   }
2070   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2071   PetscFunctionReturn(0);
2072 }
2073 
2074 #undef __FUNCT__
2075 #define __FUNCT__ "DMPlexGetJoin"
2076 /*@C
2077   DMPlexGetJoin - Get an array for the join of the set of points
2078 
2079   Not Collective
2080 
2081   Input Parameters:
2082 + dm - The DMPlex object
2083 . numPoints - The number of input points for the join
2084 - points - The input points
2085 
2086   Output Parameters:
2087 + numCoveredPoints - The number of points in the join
2088 - coveredPoints - The points in the join
2089 
2090   Level: intermediate
2091 
2092   Note: Currently, this is restricted to a single level join
2093 
2094 .keywords: mesh
2095 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2096 @*/
2097 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2098 {
2099   DM_Plex    *mesh = (DM_Plex *) dm->data;
2100   PetscInt      *join[2];
2101   PetscInt       joinSize, i = 0;
2102   PetscInt       dof, off, p, c, m;
2103   PetscErrorCode ierr;
2104 
2105   PetscFunctionBegin;
2106   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2107   PetscValidPointer(points, 2);
2108   PetscValidPointer(numCoveredPoints, 3);
2109   PetscValidPointer(coveredPoints, 4);
2110   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2111   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2112   /* Copy in support of first point */
2113   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2114   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2115   for (joinSize = 0; joinSize < dof; ++joinSize) {
2116     join[i][joinSize] = mesh->supports[off+joinSize];
2117   }
2118   /* Check each successive support */
2119   for (p = 1; p < numPoints; ++p) {
2120     PetscInt newJoinSize = 0;
2121 
2122     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2123     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2124     for (c = 0; c < dof; ++c) {
2125       const PetscInt point = mesh->supports[off+c];
2126 
2127       for (m = 0; m < joinSize; ++m) {
2128         if (point == join[i][m]) {
2129           join[1-i][newJoinSize++] = point;
2130           break;
2131         }
2132       }
2133     }
2134     joinSize = newJoinSize;
2135     i = 1-i;
2136   }
2137   *numCoveredPoints = joinSize;
2138   *coveredPoints    = join[i];
2139   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2140   PetscFunctionReturn(0);
2141 }
2142 
2143 #undef __FUNCT__
2144 #define __FUNCT__ "DMPlexRestoreJoin"
2145 /*@C
2146   DMPlexRestoreJoin - Restore an array for the join of the set of points
2147 
2148   Not Collective
2149 
2150   Input Parameters:
2151 + dm - The DMPlex object
2152 . numPoints - The number of input points for the join
2153 - points - The input points
2154 
2155   Output Parameters:
2156 + numCoveredPoints - The number of points in the join
2157 - coveredPoints - The points in the join
2158 
2159   Level: intermediate
2160 
2161 .keywords: mesh
2162 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2163 @*/
2164 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2165 {
2166   PetscErrorCode ierr;
2167 
2168   PetscFunctionBegin;
2169   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2170   PetscValidPointer(coveredPoints, 4);
2171   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2172   PetscFunctionReturn(0);
2173 }
2174 
2175 #undef __FUNCT__
2176 #define __FUNCT__ "DMPlexGetFullJoin"
2177 /*@C
2178   DMPlexGetFullJoin - Get an array for the join of the set of points
2179 
2180   Not Collective
2181 
2182   Input Parameters:
2183 + dm - The DMPlex object
2184 . numPoints - The number of input points for the join
2185 - points - The input points
2186 
2187   Output Parameters:
2188 + numCoveredPoints - The number of points in the join
2189 - coveredPoints - The points in the join
2190 
2191   Level: intermediate
2192 
2193 .keywords: mesh
2194 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2195 @*/
2196 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2197 {
2198   DM_Plex    *mesh = (DM_Plex *) dm->data;
2199   PetscInt      *offsets, **closures;
2200   PetscInt      *join[2];
2201   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2202   PetscInt       p, d, c, m;
2203   PetscErrorCode ierr;
2204 
2205   PetscFunctionBegin;
2206   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2207   PetscValidPointer(points, 2);
2208   PetscValidPointer(numCoveredPoints, 3);
2209   PetscValidPointer(coveredPoints, 4);
2210 
2211   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2212   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2213   ierr = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2214   ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2215   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2216   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2217   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2218 
2219   for (p = 0; p < numPoints; ++p) {
2220     PetscInt closureSize;
2221 
2222     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2223     offsets[p*(depth+2)+0] = 0;
2224     for (d = 0; d < depth+1; ++d) {
2225       PetscInt pStart, pEnd, i;
2226 
2227       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2228       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2229         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2230           offsets[p*(depth+2)+d+1] = i;
2231           break;
2232         }
2233       }
2234       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2235     }
2236     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);
2237   }
2238   for (d = 0; d < depth+1; ++d) {
2239     PetscInt dof;
2240 
2241     /* Copy in support of first point */
2242     dof = offsets[d+1] - offsets[d];
2243     for (joinSize = 0; joinSize < dof; ++joinSize) {
2244       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2245     }
2246     /* Check each successive cone */
2247     for (p = 1; p < numPoints && joinSize; ++p) {
2248       PetscInt newJoinSize = 0;
2249 
2250       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2251       for (c = 0; c < dof; ++c) {
2252         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2253 
2254         for (m = 0; m < joinSize; ++m) {
2255           if (point == join[i][m]) {
2256             join[1-i][newJoinSize++] = point;
2257             break;
2258           }
2259         }
2260       }
2261       joinSize = newJoinSize;
2262       i = 1-i;
2263     }
2264     if (joinSize) break;
2265   }
2266   *numCoveredPoints = joinSize;
2267   *coveredPoints    = join[i];
2268   for (p = 0; p < numPoints; ++p) {
2269     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2270   }
2271   ierr = PetscFree(closures);CHKERRQ(ierr);
2272   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2273   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2274   PetscFunctionReturn(0);
2275 }
2276 
2277 #undef __FUNCT__
2278 #define __FUNCT__ "DMPlexGetMeet"
2279 /*@C
2280   DMPlexGetMeet - Get an array for the meet of the set of points
2281 
2282   Not Collective
2283 
2284   Input Parameters:
2285 + dm - The DMPlex object
2286 . numPoints - The number of input points for the meet
2287 - points - The input points
2288 
2289   Output Parameters:
2290 + numCoveredPoints - The number of points in the meet
2291 - coveredPoints - The points in the meet
2292 
2293   Level: intermediate
2294 
2295   Note: Currently, this is restricted to a single level meet
2296 
2297 .keywords: mesh
2298 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2299 @*/
2300 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2301 {
2302   DM_Plex    *mesh = (DM_Plex *) dm->data;
2303   PetscInt      *meet[2];
2304   PetscInt       meetSize, i = 0;
2305   PetscInt       dof, off, p, c, m;
2306   PetscErrorCode ierr;
2307 
2308   PetscFunctionBegin;
2309   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2310   PetscValidPointer(points, 2);
2311   PetscValidPointer(numCoveringPoints, 3);
2312   PetscValidPointer(coveringPoints, 4);
2313   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2314   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2315   /* Copy in cone of first point */
2316   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2317   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2318   for (meetSize = 0; meetSize < dof; ++meetSize) {
2319     meet[i][meetSize] = mesh->cones[off+meetSize];
2320   }
2321   /* Check each successive cone */
2322   for (p = 1; p < numPoints; ++p) {
2323     PetscInt newMeetSize = 0;
2324 
2325     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2326     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2327     for (c = 0; c < dof; ++c) {
2328       const PetscInt point = mesh->cones[off+c];
2329 
2330       for (m = 0; m < meetSize; ++m) {
2331         if (point == meet[i][m]) {
2332           meet[1-i][newMeetSize++] = point;
2333           break;
2334         }
2335       }
2336     }
2337     meetSize = newMeetSize;
2338     i = 1-i;
2339   }
2340   *numCoveringPoints = meetSize;
2341   *coveringPoints    = meet[i];
2342   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2343   PetscFunctionReturn(0);
2344 }
2345 
2346 #undef __FUNCT__
2347 #define __FUNCT__ "DMPlexRestoreMeet"
2348 /*@C
2349   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2350 
2351   Not Collective
2352 
2353   Input Parameters:
2354 + dm - The DMPlex object
2355 . numPoints - The number of input points for the meet
2356 - points - The input points
2357 
2358   Output Parameters:
2359 + numCoveredPoints - The number of points in the meet
2360 - coveredPoints - The points in the meet
2361 
2362   Level: intermediate
2363 
2364 .keywords: mesh
2365 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2366 @*/
2367 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2368 {
2369   PetscErrorCode ierr;
2370 
2371   PetscFunctionBegin;
2372   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2373   PetscValidPointer(coveredPoints, 4);
2374   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2375   PetscFunctionReturn(0);
2376 }
2377 
2378 #undef __FUNCT__
2379 #define __FUNCT__ "DMPlexGetFullMeet"
2380 /*@C
2381   DMPlexGetFullMeet - Get an array for the meet of the set of points
2382 
2383   Not Collective
2384 
2385   Input Parameters:
2386 + dm - The DMPlex object
2387 . numPoints - The number of input points for the meet
2388 - points - The input points
2389 
2390   Output Parameters:
2391 + numCoveredPoints - The number of points in the meet
2392 - coveredPoints - The points in the meet
2393 
2394   Level: intermediate
2395 
2396 .keywords: mesh
2397 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2398 @*/
2399 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2400 {
2401   DM_Plex    *mesh = (DM_Plex *) dm->data;
2402   PetscInt      *offsets, **closures;
2403   PetscInt      *meet[2];
2404   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2405   PetscInt       p, h, c, m;
2406   PetscErrorCode ierr;
2407 
2408   PetscFunctionBegin;
2409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2410   PetscValidPointer(points, 2);
2411   PetscValidPointer(numCoveredPoints, 3);
2412   PetscValidPointer(coveredPoints, 4);
2413 
2414   ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2415   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2416   ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2417   maxSize = PetscPowInt(mesh->maxConeSize,height);
2418   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2419   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2420 
2421   for (p = 0; p < numPoints; ++p) {
2422     PetscInt closureSize;
2423 
2424     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2425     offsets[p*(height+2)+0] = 0;
2426     for (h = 0; h < height+1; ++h) {
2427       PetscInt pStart, pEnd, i;
2428 
2429       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2430       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2431         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2432           offsets[p*(height+2)+h+1] = i;
2433           break;
2434         }
2435       }
2436       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2437     }
2438     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);
2439   }
2440   for (h = 0; h < height+1; ++h) {
2441     PetscInt dof;
2442 
2443     /* Copy in cone of first point */
2444     dof = offsets[h+1] - offsets[h];
2445     for (meetSize = 0; meetSize < dof; ++meetSize) {
2446       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2447     }
2448     /* Check each successive cone */
2449     for (p = 1; p < numPoints && meetSize; ++p) {
2450       PetscInt newMeetSize = 0;
2451 
2452       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2453       for (c = 0; c < dof; ++c) {
2454         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2455 
2456         for (m = 0; m < meetSize; ++m) {
2457           if (point == meet[i][m]) {
2458             meet[1-i][newMeetSize++] = point;
2459             break;
2460           }
2461         }
2462       }
2463       meetSize = newMeetSize;
2464       i = 1-i;
2465     }
2466     if (meetSize) break;
2467   }
2468   *numCoveredPoints = meetSize;
2469   *coveredPoints    = meet[i];
2470   for (p = 0; p < numPoints; ++p) {
2471     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2472   }
2473   ierr = PetscFree(closures);CHKERRQ(ierr);
2474   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2475   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2476   PetscFunctionReturn(0);
2477 }
2478 
2479 #undef __FUNCT__
2480 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2481 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2482 {
2483   MPI_Comm       comm = ((PetscObject) dm)->comm;
2484   PetscInt       cellDim;
2485   PetscErrorCode ierr;
2486 
2487   PetscFunctionBegin;
2488   PetscValidPointer(numFaceVertices,3);
2489   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2490   switch (cellDim) {
2491   case 0:
2492     *numFaceVertices = 0;
2493     break;
2494   case 1:
2495     *numFaceVertices = 1;
2496     break;
2497   case 2:
2498     switch (numCorners) {
2499     case 3: /* triangle */
2500       *numFaceVertices = 2; /* Edge has 2 vertices */
2501       break;
2502     case 4: /* quadrilateral */
2503       *numFaceVertices = 2; /* Edge has 2 vertices */
2504       break;
2505     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2506       *numFaceVertices = 3; /* Edge has 3 vertices */
2507       break;
2508     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2509       *numFaceVertices = 3; /* Edge has 3 vertices */
2510       break;
2511     default:
2512       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2513     }
2514     break;
2515   case 3:
2516     switch (numCorners) {
2517     case 4: /* tetradehdron */
2518       *numFaceVertices = 3; /* Face has 3 vertices */
2519       break;
2520     case 6: /* tet cohesive cells */
2521       *numFaceVertices = 4; /* Face has 4 vertices */
2522       break;
2523     case 8: /* hexahedron */
2524       *numFaceVertices = 4; /* Face has 4 vertices */
2525       break;
2526     case 9: /* tet cohesive Lagrange cells */
2527       *numFaceVertices = 6; /* Face has 6 vertices */
2528       break;
2529     case 10: /* quadratic tetrahedron */
2530       *numFaceVertices = 6; /* Face has 6 vertices */
2531       break;
2532     case 12: /* hex cohesive Lagrange cells */
2533       *numFaceVertices = 6; /* Face has 6 vertices */
2534       break;
2535     case 18: /* quadratic tet cohesive Lagrange cells */
2536       *numFaceVertices = 6; /* Face has 6 vertices */
2537       break;
2538     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2539       *numFaceVertices = 9; /* Face has 9 vertices */
2540       break;
2541     default:
2542       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2543     }
2544     break;
2545   default:
2546     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2547   }
2548   PetscFunctionReturn(0);
2549 }
2550 
2551 #undef __FUNCT__
2552 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2553 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2554 {
2555   const PetscInt maxFaceCases = 30;
2556   PetscInt       numFaceCases = 0;
2557   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2558   PetscInt      *off, *adj;
2559   PetscInt      *neighborCells, *tmpClosure;
2560   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2561   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2562   PetscErrorCode ierr;
2563 
2564   PetscFunctionBegin;
2565   /* For parallel partitioning, I think you have to communicate supports */
2566   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2567   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2568   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2569   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2570   if (cEnd - cStart == 0) {
2571     if (numVertices) *numVertices = 0;
2572     if (offsets)     *offsets     = PETSC_NULL;
2573     if (adjacency)   *adjacency   = PETSC_NULL;
2574     PetscFunctionReturn(0);
2575   }
2576   numCells = cEnd - cStart;
2577   /* Setup face recognition */
2578   if (depth == 1) {
2579     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 */
2580 
2581     for (c = cStart; c < cEnd; ++c) {
2582       PetscInt corners;
2583 
2584       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2585       if (!cornersSeen[corners]) {
2586         PetscInt nFV;
2587 
2588         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2589         cornersSeen[corners] = 1;
2590         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2591         numFaceVertices[numFaceCases++] = nFV;
2592       }
2593     }
2594   }
2595   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2596   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2597   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2598   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2599   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2600   /* Count neighboring cells */
2601   for (cell = cStart; cell < cEnd; ++cell) {
2602     PetscInt numNeighbors = maxNeighbors, n;
2603 
2604     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2605     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2606     for (n = 0; n < numNeighbors; ++n) {
2607       PetscInt        cellPair[2];
2608       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2609       PetscInt        meetSize    = 0;
2610       const PetscInt *meet        = PETSC_NULL;
2611 
2612       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2613       if (cellPair[0] == cellPair[1]) continue;
2614       if (!found) {
2615         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2616         if (meetSize) {
2617           PetscInt f;
2618 
2619           for (f = 0; f < numFaceCases; ++f) {
2620             if (numFaceVertices[f] == meetSize) {
2621               found = PETSC_TRUE;
2622               break;
2623             }
2624           }
2625         }
2626         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2627       }
2628       if (found) {
2629         ++off[cell-cStart+1];
2630       }
2631     }
2632   }
2633   /* Prefix sum */
2634   for (cell = 1; cell <= numCells; ++cell) {
2635     off[cell] += off[cell-1];
2636   }
2637   if (adjacency) {
2638     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2639     /* Get neighboring cells */
2640     for (cell = cStart; cell < cEnd; ++cell) {
2641       PetscInt numNeighbors = maxNeighbors, n;
2642       PetscInt cellOffset   = 0;
2643 
2644       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2645       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2646       for (n = 0; n < numNeighbors; ++n) {
2647         PetscInt        cellPair[2];
2648         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2649         PetscInt        meetSize    = 0;
2650         const PetscInt *meet        = PETSC_NULL;
2651 
2652         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2653         if (cellPair[0] == cellPair[1]) continue;
2654         if (!found) {
2655           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2656           if (meetSize) {
2657             PetscInt f;
2658 
2659             for (f = 0; f < numFaceCases; ++f) {
2660               if (numFaceVertices[f] == meetSize) {
2661                 found = PETSC_TRUE;
2662                 break;
2663               }
2664             }
2665           }
2666           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2667         }
2668         if (found) {
2669           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2670           ++cellOffset;
2671         }
2672       }
2673     }
2674   }
2675   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2676   if (numVertices) *numVertices = numCells;
2677   if (offsets)     *offsets     = off;
2678   if (adjacency)   *adjacency   = adj;
2679   PetscFunctionReturn(0);
2680 }
2681 
2682 #if defined(PETSC_HAVE_CHACO)
2683 #if defined(PETSC_HAVE_UNISTD_H)
2684 #include <unistd.h>
2685 #endif
2686 /* Chaco does not have an include file */
2687 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2688                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2689                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2690                        int mesh_dims[3], double *goal, int global_method, int local_method,
2691                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2692 
2693 extern int FREE_GRAPH;
2694 
2695 #undef __FUNCT__
2696 #define __FUNCT__ "DMPlexPartition_Chaco"
2697 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2698 {
2699   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2700   MPI_Comm comm = ((PetscObject) dm)->comm;
2701   int nvtxs = numVertices;                /* number of vertices in full graph */
2702   int *vwgts = NULL;                      /* weights for all vertices */
2703   float *ewgts = NULL;                    /* weights for all edges */
2704   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2705   char *outassignname = NULL;             /*  name of assignment output file */
2706   char *outfilename = NULL;               /* output file name */
2707   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2708   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2709   int mesh_dims[3];                       /* dimensions of mesh of processors */
2710   double *goal = NULL;                    /* desired set sizes for each set */
2711   int global_method = 1;                  /* global partitioning algorithm */
2712   int local_method = 1;                   /* local partitioning algorithm */
2713   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2714   int vmax = 200;                         /* how many vertices to coarsen down to? */
2715   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2716   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2717   long seed = 123636512;                  /* for random graph mutations */
2718   short int *assignment;                  /* Output partition */
2719   int fd_stdout, fd_pipe[2];
2720   PetscInt      *points;
2721   PetscMPIInt    commSize;
2722   int            i, v, p;
2723   PetscErrorCode ierr;
2724 
2725   PetscFunctionBegin;
2726   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2727   if (!numVertices) {
2728     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2729     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2730     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2731     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2732     PetscFunctionReturn(0);
2733   }
2734   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2735   for (i = 0; i < start[numVertices]; ++i) {
2736     ++adjacency[i];
2737   }
2738   if (global_method == INERTIAL_METHOD) {
2739     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2740     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2741   }
2742   mesh_dims[0] = commSize;
2743   mesh_dims[1] = 1;
2744   mesh_dims[2] = 1;
2745   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2746   /* Chaco outputs to stdout. We redirect this to a buffer. */
2747   /* TODO: check error codes for UNIX calls */
2748 #if defined(PETSC_HAVE_UNISTD_H)
2749   {
2750     int piperet;
2751     piperet = pipe(fd_pipe);
2752     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2753     fd_stdout = dup(1);
2754     close(1);
2755     dup2(fd_pipe[1], 1);
2756   }
2757 #endif
2758   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2759                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2760                    vmax, ndims, eigtol, seed);
2761 #if defined(PETSC_HAVE_UNISTD_H)
2762   {
2763     char msgLog[10000];
2764     int  count;
2765 
2766     fflush(stdout);
2767     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2768     if (count < 0) count = 0;
2769     msgLog[count] = 0;
2770     close(1);
2771     dup2(fd_stdout, 1);
2772     close(fd_stdout);
2773     close(fd_pipe[0]);
2774     close(fd_pipe[1]);
2775     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2776   }
2777 #endif
2778   /* Convert to PetscSection+IS */
2779   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2780   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2781   for (v = 0; v < nvtxs; ++v) {
2782     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2783   }
2784   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2785   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2786   for (p = 0, i = 0; p < commSize; ++p) {
2787     for (v = 0; v < nvtxs; ++v) {
2788       if (assignment[v] == p) points[i++] = v;
2789     }
2790   }
2791   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2792   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2793   if (global_method == INERTIAL_METHOD) {
2794     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2795   }
2796   ierr = PetscFree(assignment);CHKERRQ(ierr);
2797   for (i = 0; i < start[numVertices]; ++i) {
2798     --adjacency[i];
2799   }
2800   PetscFunctionReturn(0);
2801 }
2802 #endif
2803 
2804 #if defined(PETSC_HAVE_PARMETIS)
2805 #undef __FUNCT__
2806 #define __FUNCT__ "DMPlexPartition_ParMetis"
2807 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2808 {
2809   PetscFunctionBegin;
2810   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2811   PetscFunctionReturn(0);
2812 }
2813 #endif
2814 
2815 #undef __FUNCT__
2816 #define __FUNCT__ "DMPlexEnlargePartition"
2817 /* Expand the partition by BFS on the adjacency graph */
2818 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2819 {
2820   PetscHashI      h;
2821   const PetscInt *points;
2822   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2823   PetscInt        pStart, pEnd, part, q;
2824   PetscErrorCode  ierr;
2825 
2826   PetscFunctionBegin;
2827   PetscHashICreate(h);
2828   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2829   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2830   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2831   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2832   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2833   for (part = pStart; part < pEnd; ++part) {
2834     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2835 
2836     PetscHashIClear(h);
2837     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2838     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2839     /* Add all existing points to h */
2840     for (p = 0; p < numPoints; ++p) {
2841       const PetscInt point = points[off+p];
2842       PetscHashIAdd(h, point, 1);
2843     }
2844     PetscHashISize(h, nP);
2845     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2846     /* Add all points in next BFS level */
2847     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2848     for (p = 0; p < numPoints; ++p) {
2849       const PetscInt point = points[off+p];
2850       PetscInt s = start[point], e = start[point+1], a;
2851 
2852       for (a = s; a < e; ++a) {
2853         PetscHashIAdd(h, adjacency[a], 1);
2854       }
2855     }
2856     PetscHashISize(h, numNewPoints);
2857     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2858     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2859     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2860     totPoints += numNewPoints;
2861   }
2862   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2863   PetscHashIDestroy(h);
2864   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2865   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2866   for (part = pStart, q = 0; part < pEnd; ++part) {
2867     PetscInt numPoints, p;
2868 
2869     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2870     for (p = 0; p < numPoints; ++p, ++q) {
2871       newPoints[q] = tmpPoints[part][p];
2872     }
2873     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2874   }
2875   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2876   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2877   PetscFunctionReturn(0);
2878 }
2879 
2880 #undef __FUNCT__
2881 #define __FUNCT__ "DMPlexCreatePartition"
2882 /*
2883   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2884 
2885   Collective on DM
2886 
2887   Input Parameters:
2888   + dm - The DM
2889   . height - The height for points in the partition
2890   - enlarge - Expand each partition with neighbors
2891 
2892   Output Parameters:
2893   + partSection - The PetscSection giving the division of points by partition
2894   . partition - The list of points by partition
2895   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2896   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2897 
2898   Level: developer
2899 
2900 .seealso DMPlexDistribute()
2901 */
2902 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2903 {
2904   PetscMPIInt    size;
2905   PetscErrorCode ierr;
2906 
2907   PetscFunctionBegin;
2908   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2909   *origPartSection = PETSC_NULL;
2910   *origPartition   = PETSC_NULL;
2911   if (size == 1) {
2912     PetscInt *points;
2913     PetscInt  cStart, cEnd, c;
2914 
2915     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2916     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2917     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2918     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2919     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2920     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2921     for (c = cStart; c < cEnd; ++c) {
2922       points[c] = c;
2923     }
2924     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2925     PetscFunctionReturn(0);
2926   }
2927   if (height == 0) {
2928     PetscInt  numVertices;
2929     PetscInt *start     = PETSC_NULL;
2930     PetscInt *adjacency = PETSC_NULL;
2931 
2932     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2933     if (1) {
2934 #if defined(PETSC_HAVE_CHACO)
2935       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2936 #endif
2937     } else {
2938 #if defined(PETSC_HAVE_PARMETIS)
2939       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2940 #endif
2941     }
2942     if (enlarge) {
2943       *origPartSection = *partSection;
2944       *origPartition   = *partition;
2945       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2946     }
2947     ierr = PetscFree(start);CHKERRQ(ierr);
2948     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2949 # if 0
2950   } else if (height == 1) {
2951     /* Build the dual graph for faces and partition the hypergraph */
2952     PetscInt numEdges;
2953 
2954     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2955     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2956     destroyCSR(numEdges, start, adjacency);
2957 #endif
2958   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2959   PetscFunctionReturn(0);
2960 }
2961 
2962 #undef __FUNCT__
2963 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2964 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2965 {
2966   /* const PetscInt  height = 0; */
2967   const PetscInt *partArray;
2968   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2969   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2970   PetscErrorCode  ierr;
2971 
2972   PetscFunctionBegin;
2973   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2974   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2975   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2976   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2977   for (rank = rStart; rank < rEnd; ++rank) {
2978     PetscInt partSize = 0;
2979     PetscInt numPoints, offset, p;
2980 
2981     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2982     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2983     for (p = 0; p < numPoints; ++p) {
2984       PetscInt  point   = partArray[offset+p], closureSize, c;
2985       PetscInt *closure = PETSC_NULL;
2986 
2987       /* TODO Include support for height > 0 case */
2988       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2989       /* Merge into existing points */
2990       if (partSize+closureSize > maxPartSize) {
2991         PetscInt *tmpPoints;
2992 
2993         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2994         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2995         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2996         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2997         partPoints = tmpPoints;
2998       }
2999       for (c = 0; c < closureSize; ++c) {
3000         partPoints[partSize+c] = closure[c*2];
3001       }
3002       partSize += closureSize;
3003       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3004       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3005     }
3006     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3007   }
3008   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3009   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3010   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3011 
3012   for (rank = rStart; rank < rEnd; ++rank) {
3013     PetscInt partSize = 0, newOffset;
3014     PetscInt numPoints, offset, p;
3015 
3016     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3017     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3018     for (p = 0; p < numPoints; ++p) {
3019       PetscInt  point   = partArray[offset+p], closureSize, c;
3020       PetscInt *closure = PETSC_NULL;
3021 
3022       /* TODO Include support for height > 0 case */
3023       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3024       /* Merge into existing points */
3025       for (c = 0; c < closureSize; ++c) {
3026         partPoints[partSize+c] = closure[c*2];
3027       }
3028       partSize += closureSize;
3029       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3030       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3031     }
3032     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3033     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3034   }
3035   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3036   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3037   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3038   PetscFunctionReturn(0);
3039 }
3040 
3041 #undef __FUNCT__
3042 #define __FUNCT__ "DMPlexDistributeField"
3043 /*
3044   Input Parameters:
3045 . originalSection
3046 , originalVec
3047 
3048   Output Parameters:
3049 . newSection
3050 . newVec
3051 */
3052 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3053 {
3054   PetscSF         fieldSF;
3055   PetscInt       *remoteOffsets, fieldSize;
3056   PetscScalar    *originalValues, *newValues;
3057   PetscErrorCode  ierr;
3058 
3059   PetscFunctionBegin;
3060   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3061 
3062   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3063   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3064   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3065 
3066   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3067   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3068   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3069   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3070   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3071   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3072   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3073   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3074   PetscFunctionReturn(0);
3075 }
3076 
3077 #undef __FUNCT__
3078 #define __FUNCT__ "DMPlexDistribute"
3079 /*@C
3080   DMPlexDistribute - Distributes the mesh and any associated sections.
3081 
3082   Not Collective
3083 
3084   Input Parameter:
3085 + dm  - The original DMPlex object
3086 . partitioner - The partitioning package, or NULL for the default
3087 - overlap - The overlap of partitions, 0 is the default
3088 
3089   Output Parameter:
3090 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3091 
3092   Note: If the mesh was not distributed, the return value is PETSC_NULL
3093 
3094   Level: intermediate
3095 
3096 .keywords: mesh, elements
3097 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3098 @*/
3099 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3100 {
3101   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3102   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3103   const PetscInt height = 0;
3104   PetscInt       dim, numRemoteRanks;
3105   IS             origCellPart,        cellPart,        part;
3106   PetscSection   origCellPartSection, cellPartSection, partSection;
3107   PetscSFNode   *remoteRanks;
3108   PetscSF        partSF, pointSF, coneSF;
3109   ISLocalToGlobalMapping renumbering;
3110   PetscSection   originalConeSection, newConeSection;
3111   PetscInt      *remoteOffsets;
3112   PetscInt      *cones, *newCones, newConesSize;
3113   PetscBool      flg;
3114   PetscMPIInt    rank, numProcs, p;
3115   PetscErrorCode ierr;
3116 
3117   PetscFunctionBegin;
3118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3119   PetscValidPointer(dmParallel,4);
3120   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3121   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3122   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3123   *dmParallel = PETSC_NULL;
3124   if (numProcs == 1) PetscFunctionReturn(0);
3125 
3126   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3127   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3128   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3129   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3130   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3131   if (!rank) {
3132     numRemoteRanks = numProcs;
3133   } else {
3134     numRemoteRanks = 0;
3135   }
3136   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3137   for (p = 0; p < numRemoteRanks; ++p) {
3138     remoteRanks[p].rank  = p;
3139     remoteRanks[p].index = 0;
3140   }
3141   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3142   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3143   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3144   if (flg) {
3145     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3146     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3147     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3148     if (origCellPart) {
3149       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3150       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3151       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3152     }
3153     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3154   }
3155   /* Close the partition over the mesh */
3156   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3157   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3158   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3159   /* Create new mesh */
3160   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3161   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3162   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3163   pmesh = (DM_Plex *) (*dmParallel)->data;
3164   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3165   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3166   if (flg) {
3167     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3168     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3169     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3170     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3171     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3172     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3173   }
3174   /* Distribute cone section */
3175   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3176   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3177   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3178   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3179   {
3180     PetscInt pStart, pEnd, p;
3181 
3182     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3183     for (p = pStart; p < pEnd; ++p) {
3184       PetscInt coneSize;
3185       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3186       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3187     }
3188   }
3189   /* Communicate and renumber cones */
3190   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3191   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3192   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3193   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3194   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3195   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3196   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3197   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3198   if (flg) {
3199     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3200     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3201     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3202     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3203     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3204   }
3205   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3206   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3207   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3208   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3209   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3210   /* Create supports and stratify sieve */
3211   {
3212     PetscInt pStart, pEnd;
3213 
3214     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3215     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3216   }
3217   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3218   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3219   /* Distribute Coordinates */
3220   {
3221     PetscSection originalCoordSection, newCoordSection;
3222     Vec          originalCoordinates, newCoordinates;
3223     const char  *name;
3224 
3225     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3226     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3227     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3228     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3229     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3230     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3231 
3232     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3233     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3234     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3235   }
3236   /* Distribute labels */
3237   {
3238     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3239     PetscInt   numLabels = 0, l;
3240 
3241     /* Bcast number of labels */
3242     while (next) {++numLabels; next = next->next;}
3243     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3244     next = mesh->labels;
3245     for (l = 0; l < numLabels; ++l) {
3246       DMLabel         newLabel;
3247       const PetscInt *partArray;
3248       char           *name;
3249       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3250       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3251       PetscInt        nameSize, s, p;
3252       PetscBool       isdepth;
3253       size_t          len = 0;
3254 
3255       /* Bcast name (could filter for no points) */
3256       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3257       nameSize = len;
3258       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3259       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3260       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3261       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3262       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3263       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3264       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3265       newLabel->name = name;
3266       /* Bcast numStrata (could filter for no points in stratum) */
3267       if (!rank) {newLabel->numStrata = next->numStrata;}
3268       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3269       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3270                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3271                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3272       /* Bcast stratumValues (could filter for no points in stratum) */
3273       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3274       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3275       /* Find size on each process and Scatter */
3276       if (!rank) {
3277         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3278         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3279         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3280         for (s = 0; s < next->numStrata; ++s) {
3281           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3282             const PetscInt point = next->points[p];
3283             PetscInt       proc;
3284 
3285             for (proc = 0; proc < numProcs; ++proc) {
3286               PetscInt dof, off, pPart;
3287 
3288               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3289               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3290               for (pPart = off; pPart < off+dof; ++pPart) {
3291                 if (partArray[pPart] == point) {
3292                   ++stratumSizes[proc*next->numStrata+s];
3293                   break;
3294                 }
3295               }
3296             }
3297           }
3298         }
3299         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3300       }
3301       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3302       /* Calculate stratumOffsets */
3303       newLabel->stratumOffsets[0] = 0;
3304       for (s = 0; s < newLabel->numStrata; ++s) {
3305         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3306       }
3307       /* Pack points and Scatter */
3308       if (!rank) {
3309         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3310         displs[0] = 0;
3311         for (p = 0; p < numProcs; ++p) {
3312           sendcnts[p] = 0;
3313           for (s = 0; s < next->numStrata; ++s) {
3314             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3315           }
3316           offsets[p]  = displs[p];
3317           displs[p+1] = displs[p] + sendcnts[p];
3318         }
3319         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3320         for (s = 0; s < next->numStrata; ++s) {
3321           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3322             const PetscInt point = next->points[p];
3323             PetscInt       proc;
3324 
3325             for (proc = 0; proc < numProcs; ++proc) {
3326               PetscInt dof, off, pPart;
3327 
3328               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3329               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3330               for (pPart = off; pPart < off+dof; ++pPart) {
3331                 if (partArray[pPart] == point) {
3332                   points[offsets[proc]++] = point;
3333                   break;
3334                 }
3335               }
3336             }
3337           }
3338         }
3339       }
3340       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3341       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3342       ierr = PetscFree(points);CHKERRQ(ierr);
3343       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3344       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3345       /* Renumber points */
3346       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3347       /* Sort points */
3348       for (s = 0; s < newLabel->numStrata; ++s) {
3349         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3350       }
3351       /* Insert into list */
3352       if (newNext) {
3353         newNext->next = newLabel;
3354       } else {
3355         pmesh->labels = newLabel;
3356       }
3357       newNext = newLabel;
3358       if (!rank) {next = next->next;}
3359     }
3360   }
3361   /* Cleanup Partition */
3362   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3363   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3364   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3365   ierr = ISDestroy(&part);CHKERRQ(ierr);
3366   /* Create point SF for parallel mesh */
3367   {
3368     const PetscInt *leaves;
3369     PetscSFNode    *remotePoints, *rowners, *lowners;
3370     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3371     PetscInt        pStart, pEnd;
3372 
3373     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3374     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3375     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3376     for (p=0; p<numRoots; p++) {
3377       rowners[p].rank = -1;
3378       rowners[p].index = -1;
3379     }
3380     if (origCellPart) {
3381       /* Make sure cells in the original partition are not assigned to other procs */
3382       const PetscInt *origCells;
3383 
3384       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3385       for (p = 0; p < numProcs; ++p) {
3386         PetscInt dof, off, d;
3387 
3388         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3389         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3390         for (d = off; d < off+dof; ++d) {
3391           rowners[origCells[d]].rank = p;
3392         }
3393       }
3394       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3395     }
3396     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3397     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3398 
3399     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3400     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3401     for (p = 0; p < numLeaves; ++p) {
3402       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3403         lowners[p].rank = rank;
3404         lowners[p].index = leaves ? leaves[p] : p;
3405       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3406         lowners[p].rank = -2;
3407         lowners[p].index = -2;
3408       }
3409     }
3410     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3411       rowners[p].rank = -3;
3412       rowners[p].index = -3;
3413     }
3414     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3415     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3416     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3417     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3418     for (p = 0; p < numLeaves; ++p) {
3419       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3420       if (lowners[p].rank != rank) ++numGhostPoints;
3421     }
3422     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3423     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3424     for (p = 0, gp = 0; p < numLeaves; ++p) {
3425       if (lowners[p].rank != rank) {
3426         ghostPoints[gp]       = leaves ? leaves[p] : p;
3427         remotePoints[gp].rank  = lowners[p].rank;
3428         remotePoints[gp].index = lowners[p].index;
3429         ++gp;
3430       }
3431     }
3432     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3433     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3434     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3435   }
3436   /* Cleanup */
3437   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3438   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3439   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3440   PetscFunctionReturn(0);
3441 }
3442 
3443 #undef __FUNCT__
3444 #define __FUNCT__ "DMPlexRenumber_Private"
3445 /*
3446   Reasons to renumber:
3447 
3448   1) Permute points, e.g. bandwidth reduction (Renumber)
3449 
3450     a) Must not mix strata
3451 
3452   2) Shift numbers for point insertion (Shift)
3453 
3454     a) Want operation brken into parts so that insertion can be interleaved
3455 
3456   renumbering - An IS which provides the new numbering
3457 */
3458 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3459 {
3460   PetscFunctionBegin;
3461   PetscFunctionReturn(0);
3462 }
3463 
3464 #undef __FUNCT__
3465 #define __FUNCT__ "DMPlexShiftPoint_Private"
3466 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3467 {
3468   if (depth < 0) return p;
3469   /* Cells    */ if (p < depthEnd[depth])   return p;
3470   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3471   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3472   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3473 }
3474 
3475 #undef __FUNCT__
3476 #define __FUNCT__ "DMPlexShiftSizes_Private"
3477 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3478 {
3479   PetscInt      *depthEnd;
3480   PetscInt       depth = 0, d, pStart, pEnd, p;
3481   PetscErrorCode ierr;
3482 
3483   PetscFunctionBegin;
3484   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3485   if (depth < 0) PetscFunctionReturn(0);
3486   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3487   /* Step 1: Expand chart */
3488   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3489   for (d = 0; d <= depth; ++d) {
3490     pEnd += depthShift[d];
3491     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3492   }
3493   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3494   /* Step 2: Set cone and support sizes */
3495   for (d = 0; d <= depth; ++d) {
3496     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3497     for (p = pStart; p < pEnd; ++p) {
3498       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3499       PetscInt size;
3500 
3501       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3502       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3503       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3504       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3505     }
3506   }
3507   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3508   PetscFunctionReturn(0);
3509 }
3510 
3511 #undef __FUNCT__
3512 #define __FUNCT__ "DMPlexShiftPoints_Private"
3513 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3514 {
3515   PetscInt      *depthEnd, *newpoints;
3516   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3517   PetscErrorCode ierr;
3518 
3519   PetscFunctionBegin;
3520   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3521   if (depth < 0) PetscFunctionReturn(0);
3522   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3523   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3524   for (d = 0; d <= depth; ++d) {
3525     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3526   }
3527   /* Step 5: Set cones and supports */
3528   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3529   for (p = pStart; p < pEnd; ++p) {
3530     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3531     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3532 
3533     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3534     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3535     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3536     for (i = 0; i < size; ++i) {
3537       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3538     }
3539     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3540     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3541     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3542     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3543     for (i = 0; i < size; ++i) {
3544       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3545     }
3546     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3547   }
3548   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3549   PetscFunctionReturn(0);
3550 }
3551 
3552 #undef __FUNCT__
3553 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3554 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3555 {
3556   PetscSection   coordSection, newCoordSection;
3557   Vec            coordinates, newCoordinates;
3558   PetscScalar   *coords, *newCoords;
3559   PetscInt      *depthEnd, coordSize;
3560   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3561   PetscErrorCode ierr;
3562 
3563   PetscFunctionBegin;
3564   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3565   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3566   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3567   for (d = 0; d <= depth; ++d) {
3568     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3569   }
3570   /* Step 8: Convert coordinates */
3571   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3572   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3573   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3574   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3575   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3576   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3577   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3578   for (v = vStartNew; v < vEndNew; ++v) {
3579     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3580     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3581   }
3582   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3583   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3584   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3585   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3586   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3587   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3588   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3589   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3590   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3591   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3592   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3593   for (v = vStart; v < vEnd; ++v) {
3594     PetscInt dof, off, noff, d;
3595 
3596     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3597     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3598     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3599     for (d = 0; d < dof; ++d) {
3600       newCoords[noff+d] = coords[off+d];
3601     }
3602   }
3603   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3604   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3605   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3606   PetscFunctionReturn(0);
3607 }
3608 
3609 #undef __FUNCT__
3610 #define __FUNCT__ "DMPlexShiftSF_Private"
3611 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3612 {
3613   PetscInt          *depthEnd;
3614   PetscInt           depth = 0, d;
3615   PetscSF            sfPoint, sfPointNew;
3616   const PetscSFNode *remotePoints;
3617   PetscSFNode       *gremotePoints;
3618   const PetscInt    *localPoints;
3619   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3620   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3621   PetscMPIInt        numProcs;
3622   PetscErrorCode     ierr;
3623 
3624   PetscFunctionBegin;
3625   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3626   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3627   for (d = 0; d <= depth; ++d) {
3628     totShift += depthShift[d];
3629     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3630   }
3631   /* Step 9: Convert pointSF */
3632   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3633   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3634   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3635   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3636   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3637   if (numRoots >= 0) {
3638     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3639     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3640     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3641     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3642     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3643     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3644     for (l = 0; l < numLeaves; ++l) {
3645       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3646       gremotePoints[l].rank  = remotePoints[l].rank;
3647       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3648     }
3649     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3650     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3651   }
3652   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3653   PetscFunctionReturn(0);
3654 }
3655 
3656 #undef __FUNCT__
3657 #define __FUNCT__ "DMPlexShiftLabels_Private"
3658 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3659 {
3660   PetscSF        sfPoint;
3661   DMLabel        vtkLabel, ghostLabel;
3662   PetscInt      *depthEnd;
3663   const PetscSFNode *leafRemote;
3664   const PetscInt    *leafLocal;
3665   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3666   PetscMPIInt    rank;
3667   PetscErrorCode ierr;
3668 
3669   PetscFunctionBegin;
3670   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3671   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3672   for (d = 0; d <= depth; ++d) {
3673     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3674   }
3675   /* Step 10: Convert labels */
3676   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3677   for (l = 0; l < numLabels; ++l) {
3678     DMLabel         label, newlabel;
3679     const char     *lname;
3680     PetscBool       isDepth;
3681     IS              valueIS;
3682     const PetscInt *values;
3683     PetscInt        numValues, val;
3684 
3685     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3686     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3687     if (isDepth) continue;
3688     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3689     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3690     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3691     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3692     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3693     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3694     for (val = 0; val < numValues; ++val) {
3695       IS              pointIS;
3696       const PetscInt *points;
3697       PetscInt        numPoints, p;
3698 
3699       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3700       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3701       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3702       for (p = 0; p < numPoints; ++p) {
3703         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3704 
3705         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3706       }
3707       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3708       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3709     }
3710     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3711     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3712   }
3713   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3714   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3715   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3716   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3717   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3718   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3719   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3720   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3721   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3722   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3723   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3724     for (; c < leafLocal[l] && c < cEnd; ++c) {
3725       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3726     }
3727     if (leafLocal[l] >= cEnd) break;
3728     if (leafRemote[l].rank == rank) {
3729       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3730     } else {
3731       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3732     }
3733   }
3734   for (; c < cEnd; ++c) {
3735     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3736   }
3737   if (0) {
3738     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3739     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3740     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3741   }
3742   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3743   for (f = fStart; f < fEnd; ++f) {
3744     PetscInt numCells;
3745 
3746     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3747     if (numCells < 2) {
3748       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3749     } else {
3750       const PetscInt *cells = PETSC_NULL;
3751       PetscInt        vA, vB;
3752 
3753       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3754       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3755       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3756       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3757     }
3758   }
3759   if (0) {
3760     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3761     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3762     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3763   }
3764   PetscFunctionReturn(0);
3765 }
3766 
3767 #undef __FUNCT__
3768 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3769 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3770 {
3771   DMLabel         label;
3772   IS              valueIS;
3773   const PetscInt *values;
3774   PetscInt       *depthShift;
3775   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3776   PetscErrorCode  ierr;
3777 
3778   PetscFunctionBegin;
3779   /* Count ghost cells */
3780   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3781   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3782   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3783   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3784   *numGhostCells = 0;
3785   for (fs = 0; fs < numFS; ++fs) {
3786     PetscInt numBdFaces;
3787 
3788     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3789     *numGhostCells += numBdFaces;
3790   }
3791   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3792   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3793   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3794   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3795   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3796   /* Step 3: Set cone/support sizes for new points */
3797   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3798   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3799     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3800   }
3801   for (fs = 0; fs < numFS; ++fs) {
3802     IS              faceIS;
3803     const PetscInt *faces;
3804     PetscInt        numFaces, f;
3805 
3806     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3807     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3808     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3809     for (f = 0; f < numFaces; ++f) {
3810       PetscInt size;
3811 
3812       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3813       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3814       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3815     }
3816     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3817     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3818   }
3819   /* Step 4: Setup ghosted DM */
3820   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3821   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3822   /* Step 6: Set cones and supports for new points */
3823   ghostCell = cEnd;
3824   for (fs = 0; fs < numFS; ++fs) {
3825     IS              faceIS;
3826     const PetscInt *faces;
3827     PetscInt        numFaces, f;
3828 
3829     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3830     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3831     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3832     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3833       PetscInt newFace = faces[f] + *numGhostCells;
3834 
3835       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3836       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3837     }
3838     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3839     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3840   }
3841   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3842   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3843   /* Step 7: Stratify */
3844   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3845   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3846   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3847   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3848   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3849   PetscFunctionReturn(0);
3850 }
3851 
3852 #undef __FUNCT__
3853 #define __FUNCT__ "DMPlexConstructGhostCells"
3854 /*@C
3855   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3856 
3857   Collective on dm
3858 
3859   Input Parameters:
3860 + dm - The original DM
3861 - labelName - The label specifying the boundary faces (this could be auto-generated)
3862 
3863   Output Parameters:
3864 + numGhostCells - The number of ghost cells added to the DM
3865 - dmGhosted - The new DM
3866 
3867   Level: developer
3868 
3869 .seealso: DMCreate()
3870 */
3871 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3872 {
3873   DM             gdm;
3874   PetscInt       dim;
3875   PetscErrorCode ierr;
3876 
3877   PetscFunctionBegin;
3878   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3879   PetscValidPointer(numGhostCells, 3);
3880   PetscValidPointer(dmGhosted, 4);
3881   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3882   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3883   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3884   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3885   switch (dim) {
3886   case 2:
3887     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3888     break;
3889   default:
3890     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3891   }
3892   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3893   *dmGhosted = gdm;
3894   PetscFunctionReturn(0);
3895 }
3896 
3897 #undef __FUNCT__
3898 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3899 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, const char labelName[], DM sdm)
3900 {
3901   MPI_Comm        comm = ((PetscObject) dm)->comm;
3902   DMLabel         label;
3903   IS              valueIS, *pointIS;
3904   const PetscInt *values, **splitPoints;
3905   PetscSection    coordSection;
3906   Vec             coordinates;
3907   PetscScalar    *coords;
3908   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3909   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3910   PetscErrorCode  ierr;
3911 
3912   PetscFunctionBegin;
3913   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3914   /* Count split points and add cohesive cells */
3915   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3916   if (label) {
3917     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3918     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3919     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3920   }
3921   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3922   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3923   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3924   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3925   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3926   for(d = 0; d <= depth; ++d) {
3927     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3928     numSplitPoints[d] = 0;
3929     splitPoints[d]    = PETSC_NULL;
3930     pointIS[d]        = PETSC_NULL;
3931   }
3932   for(sp = 0; sp < numSP; ++sp) {
3933     const PetscInt dep = values[sp];
3934 
3935     if ((dep < 0) || (dep > depth)) continue;
3936     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3937     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3938     if (pointIS[dep]) {
3939       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3940       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3941     }
3942   }
3943   if (depth >= 0) {
3944     /* Calculate number of additional points */
3945     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3946     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3947     /* Calculate hybrid bound for each dimension */
3948     pMaxNew[0]       += depthShift[depth];
3949     if (depth > 1) {pMaxNew[dim-1] += depthShift[depth] + depthShift[0];}
3950     if (depth > 2) {pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];}
3951     /* Calculate point offset for each dimension */
3952     depthOffset[depth] = 0;
3953     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3954     if (depth > 1) {depthOffset[dim-1] = depthOffset[0]     + depthShift[0];}
3955     if (depth > 2) {depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];}
3956   }
3957   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3958   /* Step 3: Set cone/support sizes for new points */
3959   for(dep = 0; dep <= depth; ++dep) {
3960     for(p = 0; p < numSplitPoints[dep]; ++p) {
3961       const PetscInt  oldp   = splitPoints[dep][p];
3962       const PetscInt  newp   = depthOffset[dep] + oldp;
3963       const PetscInt  splitp = pMaxNew[dep] + p;
3964       const PetscInt *support;
3965       PetscInt        coneSize, supportSize, q, e;
3966 
3967       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3968       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3969       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3970       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3971       if (dep == depth-1) {
3972         const PetscInt ccell = pMaxNew[depth] + p;
3973         /* Add cohesive cells, they are prisms */
3974         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3975       } else if (dep == 0) {
3976         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3977 
3978         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3979         /* Split old vertex: Edges in old split faces and new cohesive edge */
3980         for(e = 0, q = 0; e < supportSize; ++e) {
3981           PetscInt val;
3982 
3983           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3984           if ((val == 1) || (val == (shift + 1))) ++q;
3985         }
3986         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3987         /* Split new vertex: Edges in new split faces and new cohesive edge */
3988         for(e = 0, q = 0; e < supportSize; ++e) {
3989           PetscInt val;
3990 
3991           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3992           if ((val == 1) || (val == -(shift + 1))) ++q;
3993         }
3994         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
3995         /* Add cohesive edges */
3996         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
3997         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
3998       } else if (dep == dim-2) {
3999         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4000         /* Split old edge: Faces in positive side cells and old split faces */
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 == dim-1) || (val == (shift + dim-1))) ++q;
4006         }
4007         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4008         /* Split new edge: Faces in negative side cells and new split faces */
4009         for(e = 0, q = 0; e < supportSize; ++e) {
4010           PetscInt val;
4011 
4012           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4013           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4014         }
4015         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4016       }
4017     }
4018   }
4019   /* Step 4: Setup split DM */
4020   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4021   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4022   /* Step 6: Set cones and supports for new points */
4023   for(dep = 0; dep <= depth; ++dep) {
4024     for(p = 0; p < numSplitPoints[dep]; ++p) {
4025       const PetscInt  oldp   = splitPoints[dep][p];
4026       const PetscInt  newp   = depthOffset[dep] + oldp;
4027       const PetscInt  splitp = pMaxNew[dep] + p;
4028       const PetscInt *cone, *support, *ornt;
4029       PetscInt        coneSize, supportSize, q, v, e, s;
4030 
4031       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4032       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4033       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4034       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4035       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4036       if (dep == depth-1) {
4037         const PetscInt  ccell = pMaxNew[depth] + p;
4038         const PetscInt *supportF;
4039 
4040         /* Split face:       copy in old face to new face to start */
4041         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4042         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4043         /* Split old face:   old vertices/edges in cone so no change */
4044         /* Split new face:   new vertices/edges in cone */
4045         for(q = 0; q < coneSize; ++q) {
4046           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4047           coneNew[2+q] = pMaxNew[dim-2] + v;
4048         }
4049         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4050         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4051         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4052         coneNew[0] = newp;
4053         coneNew[1] = splitp;
4054         for(q = 0; q < coneSize; ++q) {
4055           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4056         }
4057         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4058 
4059 
4060         for(s = 0; s < supportSize; ++s) {
4061           PetscInt val;
4062 
4063           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4064           if (val < 0) {
4065             const PetscInt *scone;
4066             PetscInt        sconeSize, sc;
4067 
4068             /* Split old face:   Replace negative side cell with cohesive cell */
4069             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4070           } else {
4071             /* Split new face:   Replace positive side cell with cohesive cell */
4072             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4073           }
4074         }
4075       } else if (dep == 0) {
4076         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4077 
4078         /* Split old vertex: Edges in old split faces and new cohesive edge */
4079         for(e = 0, q = 0; e < supportSize; ++e) {
4080           PetscInt val;
4081 
4082           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4083           if ((val == 1) || (val == (shift + 1))) {
4084             supportNew[q++] = depthOffset[1] + support[e];
4085           }
4086         }
4087         supportNew[q] = cedge;
4088         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4089         /* Split new vertex: Edges in new split faces and new cohesive edge */
4090         for(e = 0, q = 0; e < supportSize; ++e) {
4091           PetscInt val, edge;
4092 
4093           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4094           if (val == 1) {
4095             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4096             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4097             supportNew[q++] = pMaxNew[1] + edge;
4098           } else if (val == -(shift + 1)) {
4099             supportNew[q++] = depthOffset[1] + support[e];
4100           }
4101         }
4102         supportNew[q] = cedge;
4103         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4104         /* Cohesive edge:    Old and new split vertex, punting on support */
4105         coneNew[0] = newp;
4106         coneNew[1] = splitp;
4107         ierr = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4108       } else if (dep == dim-2) {
4109         /* Split old edge:   old vertices in cone so no change */
4110         /* Split new edge:   new vertices in cone */
4111         for(q = 0; q < coneSize; ++q) {
4112           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4113           coneNew[q] = pMaxNew[dim-3] + v;
4114         }
4115         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4116         /* Split old edge: Faces in positive side cells and old split faces */
4117         for(e = 0, q = 0; e < supportSize; ++e) {
4118           PetscInt val;
4119 
4120           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4121           if ((val == dim-1) || (val == (shift + dim-1))) {
4122             supportNew[q++] = depthOffset[dim-1] + support[e];
4123           }
4124         }
4125         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4126         /* Split new edge: Faces in negative side cells and new split faces */
4127         for(e = 0, q = 0; e < supportSize; ++e) {
4128           PetscInt val, face;
4129 
4130           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4131           if (val == dim-1) {
4132             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4133             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4134             supportNew[q++] = pMaxNew[dim-1] + face;
4135           } else if (val == -(shift + dim-1)) {
4136             supportNew[q++] = depthOffset[dim-1] + support[e];
4137           }
4138         }
4139         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4140       }
4141     }
4142   }
4143   /* Step 6b: Replace split points in negative side cones */
4144   for(sp = 0; sp < numSP; ++sp) {
4145     PetscInt        dep = values[sp];
4146     IS              pIS;
4147     PetscInt        numPoints;
4148     const PetscInt *points;
4149 
4150     if (dep >= 0) continue;
4151     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4152     if (!pIS) continue;
4153     dep  = -dep - shift;
4154     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4155     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4156     for(p = 0; p < numPoints; ++p) {
4157       const PetscInt  oldp   = points[p];
4158       const PetscInt  newp   = depthOffset[dep] + oldp;
4159       const PetscInt  splitp = pMaxNew[dep] + p;
4160       const PetscInt *cone;
4161       PetscInt        coneSize, c;
4162       PetscBool       replaced = PETSC_FALSE;
4163 
4164       /* Negative edge: replace split vertex */
4165       /* Negative cell: replace split face */
4166       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4167       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4168       for(c = 0; c < coneSize; ++c) {
4169         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4170         PetscInt       csplitp, cp, val;
4171 
4172         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4173         if (val == dep-1) {
4174           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4175           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4176           csplitp = pMaxNew[dep-1] + cp;
4177           ierr = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4178           replaced = PETSC_TRUE;
4179         }
4180       }
4181       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4182     }
4183     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4184     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4185   }
4186   /* Step 7: Stratify */
4187   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4188   /* Step 8: Coordinates */
4189   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4190   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4191   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4192   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4193   for(v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4194     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4195     const PetscInt splitp = pMaxNew[0] + v;
4196     PetscInt       dof, off, soff, d;
4197 
4198     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4199     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4200     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4201     for(d = 0; d < dof; ++d) {
4202       coords[soff+d] = coords[off+d];
4203     }
4204   }
4205   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4206   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4207   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4208   /* Step 10: Labels */
4209   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4210   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4211   for (dep = 0; dep <= depth; ++dep) {
4212     for (p = 0; p < numSplitPoints[dep]; ++p) {
4213       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4214       const PetscInt splitp = pMaxNew[dep] + p;
4215       PetscInt       l;
4216 
4217       for (l = 0; l < numLabels; ++l) {
4218         DMLabel     label;
4219         const char *lname;
4220         PetscInt    val;
4221 
4222         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4223         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4224         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4225         if (val >= 0) {
4226           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4227           if (dep == 0) {
4228             const PetscInt cedge  = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4229             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4230           }
4231         }
4232       }
4233     }
4234   }
4235   for (sp = 0; sp < numSP; ++sp) {
4236     const PetscInt dep = values[sp];
4237 
4238     if ((dep < 0) || (dep > depth)) continue;
4239     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4240     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4241   }
4242   if (label) {
4243     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4244     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4245   }
4246   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4247   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4248   PetscFunctionReturn(0);
4249 }
4250 
4251 #undef __FUNCT__
4252 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4253 /*@C
4254   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4255 
4256   Collective on dm
4257 
4258   Input Parameters:
4259 + dm - The original DM
4260 - labelName - The label specifying the boundary faces (this could be auto-generated)
4261 
4262   Output Parameters:
4263 - dmSplit - The new DM
4264 
4265   Level: developer
4266 
4267 .seealso: DMCreate()
4268 */
4269 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4270 {
4271   DM             sdm;
4272   PetscInt       dim;
4273   PetscErrorCode ierr;
4274 
4275   PetscFunctionBegin;
4276   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4277   PetscValidPointer(dmSplit, 4);
4278   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4279   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4280   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4281   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4282   switch(dim) {
4283   case 2:
4284   case 3:
4285     ierr = DMPlexConstructCohesiveCells_Private(dm, labelName, sdm);CHKERRQ(ierr);
4286     break;
4287   default:
4288     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4289   }
4290   *dmSplit = sdm;
4291   PetscFunctionReturn(0);
4292 }
4293 
4294 #undef __FUNCT__
4295 #define __FUNCT__ "DMLabelCohesiveComplete"
4296 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4297 {
4298   IS              dimIS;
4299   const PetscInt *points;
4300   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4301   PetscErrorCode  ierr;
4302 
4303   PetscFunctionBegin;
4304   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4305   /* Cell orientation for face gives the side of the fault */
4306   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4307   if (!dimIS) PetscFunctionReturn(0);
4308   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4309   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4310   for(p = 0; p < numPoints; ++p) {
4311     const PetscInt *support;
4312     PetscInt        supportSize, s;
4313 
4314     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4315     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4316     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4317     for(s = 0; s < supportSize; ++s) {
4318       const PetscInt *cone, *ornt;
4319       PetscInt        coneSize, c;
4320       PetscBool       pos = PETSC_TRUE;
4321 
4322       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4323       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4324       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4325       for(c = 0; c < coneSize; ++c) {
4326         if (cone[c] == points[p]) {
4327           if (ornt[c] >= 0) {
4328             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4329           } else {
4330             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4331             pos  = PETSC_FALSE;
4332           }
4333           break;
4334         }
4335       }
4336       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]);
4337       /* Put faces touching the fault in the label */
4338       for(c = 0; c < coneSize; ++c) {
4339         const PetscInt point = cone[c];
4340 
4341         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4342         if (val == -1) {
4343           PetscInt *closure = PETSC_NULL;
4344           PetscInt  closureSize, cl;
4345 
4346           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4347           for (cl = 0; cl < closureSize*2; cl += 2) {
4348             const PetscInt clp = closure[cl];
4349 
4350             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4351             if ((val >= 0) && (val < dim-1)) {
4352               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4353               break;
4354             }
4355           }
4356           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4357         }
4358       }
4359     }
4360   }
4361   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4362   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4363   /* Search for other cells/faces/edges connected to the fault by a vertex */
4364   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4365   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4366   if (!dimIS) PetscFunctionReturn(0);
4367   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4368   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4369   for(p = 0; p < numPoints; ++p) {
4370     PetscInt *star = PETSC_NULL;
4371     PetscInt  starSize, s;
4372     PetscInt  again = 1; /* 0: Finished 1: Keep iterating after a change 2: No change */
4373 
4374     /* First mark cells connected to the fault */
4375     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4376     while (again) {
4377       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4378       again = 0;
4379       for (s = 0; s < starSize*2; s += 2) {
4380         const PetscInt  point = star[s];
4381         const PetscInt *cone;
4382         PetscInt        coneSize, c;
4383 
4384         if ((point < cStart) || (point >= cEnd)) continue;
4385         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4386         if (val != -1) continue;
4387         again = 2;
4388         ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4389         ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4390         for(c = 0; c < coneSize; ++c) {
4391           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4392           if (val != -1) {
4393             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);
4394             if (val > 0) {
4395               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4396             } else {
4397               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4398             }
4399             again = 1;
4400             break;
4401           }
4402         }
4403       }
4404     }
4405     /* Classify the rest by cell membership */
4406     for (s = 0; s < starSize*2; s += 2) {
4407       const PetscInt point = star[s];
4408 
4409       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4410       if (val == -1) {
4411         PetscInt *sstar = PETSC_NULL;
4412         PetscInt  sstarSize, ss;
4413         PetscBool marked = PETSC_FALSE;
4414 
4415         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4416         for (ss = 0; ss < sstarSize*2; ss += 2) {
4417           const PetscInt spoint = sstar[ss];
4418 
4419           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4420           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4421           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4422           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4423           if (val > 0) {
4424             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4425           } else {
4426             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4427           }
4428           marked = PETSC_TRUE;
4429           break;
4430         }
4431         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4432         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4433       }
4434     }
4435     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4436   }
4437   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4438   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4439   PetscFunctionReturn(0);
4440 }
4441 
4442 #undef __FUNCT__
4443 #define __FUNCT__ "DMPlexInterpolate_2D"
4444 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4445 {
4446   DM             idm;
4447   DM_Plex       *mesh;
4448   PetscHashIJ    edgeTable;
4449   PetscInt      *off;
4450   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4451   PetscInt       numEdges, firstEdge, edge, e;
4452   PetscErrorCode ierr;
4453 
4454   PetscFunctionBegin;
4455   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4456   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4457   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4458   numCells    = cEnd - cStart;
4459   numVertices = vEnd - vStart;
4460   firstEdge   = numCells + numVertices;
4461   numEdges    = 0 ;
4462   /* Count edges using algorithm from CreateNeighborCSR */
4463   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4464   if (off) {
4465     PetscInt numCorners = 0;
4466 
4467     numEdges = off[numCells]/2;
4468 #if 0
4469     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4470     numEdges += 3*numCells - off[numCells];
4471 #else
4472     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4473     for (c = cStart; c < cEnd; ++c) {
4474       PetscInt coneSize;
4475 
4476       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4477       numCorners += coneSize;
4478     }
4479     numEdges += numCorners - off[numCells];
4480 #endif
4481   }
4482 #if 0
4483   /* Check Euler characteristic V - E + F = 1 */
4484   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4485 #endif
4486   /* Create interpolated mesh */
4487   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4488   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4489   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4490   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4491   for (c = 0; c < numCells; ++c) {
4492     PetscInt numCorners;
4493 
4494     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4495     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4496   }
4497   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4498     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4499   }
4500   ierr = DMSetUp(idm);CHKERRQ(ierr);
4501   /* Get edge cones from subsets of cell vertices */
4502   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4503   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4504 
4505   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4506     const PetscInt *cellFaces;
4507     PetscInt        numCellFaces, faceSize, cf;
4508 
4509     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4510     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4511     for (cf = 0; cf < numCellFaces; ++cf) {
4512 #if 1
4513       PetscHashIJKey key;
4514 
4515       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4516       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4517       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4518       if (e < 0) {
4519         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4520         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4521         e    = edge++;
4522       }
4523 #else
4524       PetscBool found = PETSC_FALSE;
4525 
4526       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4527       for (e = firstEdge; e < edge; ++e) {
4528         const PetscInt *cone;
4529 
4530         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4531         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4532             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4533           found = PETSC_TRUE;
4534           break;
4535         }
4536       }
4537       if (!found) {
4538         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4539         ++edge;
4540       }
4541 #endif
4542       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4543     }
4544   }
4545   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4546   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4547   ierr = PetscFree(off);CHKERRQ(ierr);
4548   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4549   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4550   mesh = (DM_Plex *) (idm)->data;
4551   /* Orient edges */
4552   for (c = 0; c < numCells; ++c) {
4553     const PetscInt *cone = PETSC_NULL, *cellFaces;
4554     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4555 
4556     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4557     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4558     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4559     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4560     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4561     for (cf = 0; cf < numCellFaces; ++cf) {
4562       const PetscInt *econe = PETSC_NULL;
4563       PetscInt        esize;
4564 
4565       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4566       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4567       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]);
4568       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4569         /* Correctly oriented */
4570         mesh->coneOrientations[coff+cf] = 0;
4571       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4572         /* Start at index 1, and reverse orientation */
4573         mesh->coneOrientations[coff+cf] = -(1+1);
4574       }
4575     }
4576   }
4577   *dmInt  = idm;
4578   PetscFunctionReturn(0);
4579 }
4580 
4581 #undef __FUNCT__
4582 #define __FUNCT__ "DMPlexInterpolate_3D"
4583 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4584 {
4585   DM             idm, fdm;
4586   DM_Plex    *mesh;
4587   PetscInt      *off;
4588   const PetscInt numCorners = 4;
4589   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4590   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4591   PetscErrorCode ierr;
4592 
4593   PetscFunctionBegin;
4594   {
4595     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4596     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4597     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4598   }
4599   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4600   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4601   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4602   numCells    = cEnd - cStart;
4603   numVertices = vEnd - vStart;
4604   firstFace   = numCells + numVertices;
4605   numFaces    = 0 ;
4606   /* Count faces using algorithm from CreateNeighborCSR */
4607   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4608   if (off) {
4609     numFaces = off[numCells]/2;
4610     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4611     numFaces += 4*numCells - off[numCells];
4612   }
4613   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4614   firstEdge = firstFace + numFaces;
4615   numEdges  = numVertices + numFaces - numCells - 1;
4616   /* Create interpolated mesh */
4617   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4618   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4619   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4620   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4621   for (c = 0; c < numCells; ++c) {
4622     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4623   }
4624   for (f = firstFace; f < firstFace+numFaces; ++f) {
4625     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4626   }
4627   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4628     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4629   }
4630   ierr = DMSetUp(idm);CHKERRQ(ierr);
4631   /* Get face cones from subsets of cell vertices */
4632   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4633   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4634   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4635   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4636   for (f = firstFace; f < firstFace+numFaces; ++f) {
4637     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4638   }
4639   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4640   for (c = 0, face = firstFace; c < numCells; ++c) {
4641     const PetscInt *cellFaces;
4642     PetscInt        numCellFaces, faceSize, cf;
4643 
4644     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4645     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4646     for (cf = 0; cf < numCellFaces; ++cf) {
4647       PetscBool found = PETSC_FALSE;
4648 
4649       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4650       for (f = firstFace; f < face; ++f) {
4651         const PetscInt *cone = PETSC_NULL;
4652 
4653         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4654         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4655             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4656             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4657             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4658             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4659             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4660           found = PETSC_TRUE;
4661           break;
4662         }
4663       }
4664       if (!found) {
4665         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4666         /* Save the vertices for orientation calculation */
4667         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4668         ++face;
4669       }
4670       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4671     }
4672   }
4673   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4674   /* Get edge cones from subsets of face vertices */
4675   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4676     const PetscInt *cellFaces;
4677     PetscInt        numCellFaces, faceSize, cf;
4678 
4679     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4680     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4681     for (cf = 0; cf < numCellFaces; ++cf) {
4682       PetscBool found = PETSC_FALSE;
4683 
4684       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4685       for (e = firstEdge; e < edge; ++e) {
4686         const PetscInt *cone = PETSC_NULL;
4687 
4688         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4689         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4690             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4691           found = PETSC_TRUE;
4692           break;
4693         }
4694       }
4695       if (!found) {
4696         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4697         ++edge;
4698       }
4699       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4700     }
4701   }
4702   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4703   ierr = PetscFree(off);CHKERRQ(ierr);
4704   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4705   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4706   mesh = (DM_Plex *) (idm)->data;
4707   /* Orient edges */
4708   for (f = firstFace; f < firstFace+numFaces; ++f) {
4709     const PetscInt *cone, *cellFaces;
4710     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4711 
4712     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4713     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4714     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4715     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4716     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4717     for (cf = 0; cf < numCellFaces; ++cf) {
4718       const PetscInt *econe;
4719       PetscInt        esize;
4720 
4721       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4722       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4723       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]);
4724       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4725         /* Correctly oriented */
4726         mesh->coneOrientations[coff+cf] = 0;
4727       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4728         /* Start at index 1, and reverse orientation */
4729         mesh->coneOrientations[coff+cf] = -(1+1);
4730       }
4731     }
4732   }
4733   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4734   /* Orient faces */
4735   for (c = 0; c < numCells; ++c) {
4736     const PetscInt *cone, *cellFaces;
4737     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4738 
4739     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4740     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4741     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4742     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4743     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4744     for (cf = 0; cf < numCellFaces; ++cf) {
4745       PetscInt *origClosure = PETSC_NULL, *closure;
4746       PetscInt  closureSize, i;
4747 
4748       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4749       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4750       for (i = 4; i < 7; ++i) {
4751         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);
4752       }
4753       closure = &origClosure[4*2];
4754       /* Remember that this is the orientation for edges, not vertices */
4755       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4756         /* Correctly oriented */
4757         mesh->coneOrientations[coff+cf] = 0;
4758       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4759         /* Shifted by 1 */
4760         mesh->coneOrientations[coff+cf] = 1;
4761       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4762         /* Shifted by 2 */
4763         mesh->coneOrientations[coff+cf] = 2;
4764       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4765         /* Start at edge 1, and reverse orientation */
4766         mesh->coneOrientations[coff+cf] = -(1+1);
4767       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4768         /* Start at index 0, and reverse orientation */
4769         mesh->coneOrientations[coff+cf] = -(0+1);
4770       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4771         /* Start at index 2, and reverse orientation */
4772         mesh->coneOrientations[coff+cf] = -(2+1);
4773       } 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);
4774       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4775     }
4776   }
4777   {
4778     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4779     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4780     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4781   }
4782   *dmInt  = idm;
4783   PetscFunctionReturn(0);
4784 }
4785 
4786 #undef __FUNCT__
4787 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4788 /*
4789   This takes as input the common mesh generator output, a list of the vertices for each cell
4790 */
4791 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4792 {
4793   PetscInt      *cone, c, p;
4794   PetscErrorCode ierr;
4795 
4796   PetscFunctionBegin;
4797   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4798   for (c = 0; c < numCells; ++c) {
4799     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4800   }
4801   ierr = DMSetUp(dm);CHKERRQ(ierr);
4802   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4803   for (c = 0; c < numCells; ++c) {
4804     for (p = 0; p < numCorners; ++p) {
4805       cone[p] = cells[c*numCorners+p]+numCells;
4806     }
4807     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4808   }
4809   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4810   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4811   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4812   PetscFunctionReturn(0);
4813 }
4814 
4815 #undef __FUNCT__
4816 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4817 /*
4818   This takes as input the coordinates for each vertex
4819 */
4820 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4821 {
4822   PetscSection   coordSection;
4823   Vec            coordinates;
4824   PetscScalar   *coords;
4825   PetscInt       coordSize, v, d;
4826   PetscErrorCode ierr;
4827 
4828   PetscFunctionBegin;
4829   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4830   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4831   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4832   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4833   for (v = numCells; v < numCells+numVertices; ++v) {
4834     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4835     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4836   }
4837   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4838   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4839   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4840   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4841   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4842   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4843   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4844   for (v = 0; v < numVertices; ++v) {
4845     for (d = 0; d < spaceDim; ++d) {
4846       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4847     }
4848   }
4849   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4850   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4851   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4852   PetscFunctionReturn(0);
4853 }
4854 
4855 #undef __FUNCT__
4856 #define __FUNCT__ "DMPlexCreateFromCellList"
4857 /*
4858   This takes as input the common mesh generator output, a list of the vertices for each cell
4859 */
4860 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4861 {
4862   PetscErrorCode ierr;
4863 
4864   PetscFunctionBegin;
4865   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4866   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4867   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4868   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4869   if (interpolate) {
4870     DM idm;
4871 
4872     switch (dim) {
4873     case 2:
4874       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4875     case 3:
4876       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4877     default:
4878       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4879     }
4880     ierr = DMDestroy(dm);CHKERRQ(ierr);
4881     *dm  = idm;
4882   }
4883   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4884   PetscFunctionReturn(0);
4885 }
4886 
4887 #if defined(PETSC_HAVE_TRIANGLE)
4888 #include <triangle.h>
4889 
4890 #undef __FUNCT__
4891 #define __FUNCT__ "InitInput_Triangle"
4892 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4893 {
4894   PetscFunctionBegin;
4895   inputCtx->numberofpoints = 0;
4896   inputCtx->numberofpointattributes = 0;
4897   inputCtx->pointlist = PETSC_NULL;
4898   inputCtx->pointattributelist = PETSC_NULL;
4899   inputCtx->pointmarkerlist = PETSC_NULL;
4900   inputCtx->numberofsegments = 0;
4901   inputCtx->segmentlist = PETSC_NULL;
4902   inputCtx->segmentmarkerlist = PETSC_NULL;
4903   inputCtx->numberoftriangleattributes = 0;
4904   inputCtx->trianglelist = PETSC_NULL;
4905   inputCtx->numberofholes = 0;
4906   inputCtx->holelist = PETSC_NULL;
4907   inputCtx->numberofregions = 0;
4908   inputCtx->regionlist = PETSC_NULL;
4909   PetscFunctionReturn(0);
4910 }
4911 
4912 #undef __FUNCT__
4913 #define __FUNCT__ "InitOutput_Triangle"
4914 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4915 {
4916   PetscFunctionBegin;
4917   outputCtx->numberofpoints = 0;
4918   outputCtx->pointlist = PETSC_NULL;
4919   outputCtx->pointattributelist = PETSC_NULL;
4920   outputCtx->pointmarkerlist = PETSC_NULL;
4921   outputCtx->numberoftriangles = 0;
4922   outputCtx->trianglelist = PETSC_NULL;
4923   outputCtx->triangleattributelist = PETSC_NULL;
4924   outputCtx->neighborlist = PETSC_NULL;
4925   outputCtx->segmentlist = PETSC_NULL;
4926   outputCtx->segmentmarkerlist = PETSC_NULL;
4927   outputCtx->numberofedges = 0;
4928   outputCtx->edgelist = PETSC_NULL;
4929   outputCtx->edgemarkerlist = PETSC_NULL;
4930   PetscFunctionReturn(0);
4931 }
4932 
4933 #undef __FUNCT__
4934 #define __FUNCT__ "FiniOutput_Triangle"
4935 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4936 {
4937   PetscFunctionBegin;
4938   free(outputCtx->pointmarkerlist);
4939   free(outputCtx->edgelist);
4940   free(outputCtx->edgemarkerlist);
4941   free(outputCtx->trianglelist);
4942   free(outputCtx->neighborlist);
4943   PetscFunctionReturn(0);
4944 }
4945 
4946 #undef __FUNCT__
4947 #define __FUNCT__ "DMPlexGenerate_Triangle"
4948 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4949 {
4950   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4951   PetscInt             dim              = 2;
4952   const PetscBool      createConvexHull = PETSC_FALSE;
4953   const PetscBool      constrained      = PETSC_FALSE;
4954   struct triangulateio in;
4955   struct triangulateio out;
4956   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4957   PetscMPIInt          rank;
4958   PetscErrorCode       ierr;
4959 
4960   PetscFunctionBegin;
4961   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4962   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4963   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4964   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4965   in.numberofpoints = vEnd - vStart;
4966   if (in.numberofpoints > 0) {
4967     PetscSection coordSection;
4968     Vec          coordinates;
4969     PetscScalar *array;
4970 
4971     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4972     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4973     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4974     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4975     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4976     for (v = vStart; v < vEnd; ++v) {
4977       const PetscInt idx = v - vStart;
4978       PetscInt       off, d;
4979 
4980       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4981       for (d = 0; d < dim; ++d) {
4982         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4983       }
4984       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4985     }
4986     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4987   }
4988   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4989   in.numberofsegments = eEnd - eStart;
4990   if (in.numberofsegments > 0) {
4991     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4992     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4993     for (e = eStart; e < eEnd; ++e) {
4994       const PetscInt  idx = e - eStart;
4995       const PetscInt *cone;
4996 
4997       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4998       in.segmentlist[idx*2+0] = cone[0] - vStart;
4999       in.segmentlist[idx*2+1] = cone[1] - vStart;
5000       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5001     }
5002   }
5003 #if 0 /* Do not currently support holes */
5004   PetscReal *holeCoords;
5005   PetscInt   h, d;
5006 
5007   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5008   if (in.numberofholes > 0) {
5009     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5010     for (h = 0; h < in.numberofholes; ++h) {
5011       for (d = 0; d < dim; ++d) {
5012         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5013       }
5014     }
5015   }
5016 #endif
5017   if (!rank) {
5018     char args[32];
5019 
5020     /* Take away 'Q' for verbose output */
5021     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5022     if (createConvexHull) {
5023       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5024     }
5025     if (constrained) {
5026       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5027     }
5028     triangulate(args, &in, &out, PETSC_NULL);
5029   }
5030   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5031   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5032   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5033   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5034   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5035 
5036   {
5037     const PetscInt numCorners  = 3;
5038     const PetscInt numCells    = out.numberoftriangles;
5039     const PetscInt numVertices = out.numberofpoints;
5040     const int     *cells       = out.trianglelist;
5041     const double  *meshCoords  = out.pointlist;
5042 
5043     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5044     /* Set labels */
5045     for (v = 0; v < numVertices; ++v) {
5046       if (out.pointmarkerlist[v]) {
5047         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5048       }
5049     }
5050     if (interpolate) {
5051       for (e = 0; e < out.numberofedges; e++) {
5052         if (out.edgemarkerlist[e]) {
5053           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5054           const PetscInt *edges;
5055           PetscInt        numEdges;
5056 
5057           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5058           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5059           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5060           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5061         }
5062       }
5063     }
5064     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5065   }
5066 #if 0 /* Do not currently support holes */
5067   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5068 #endif
5069   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5070   PetscFunctionReturn(0);
5071 }
5072 
5073 #undef __FUNCT__
5074 #define __FUNCT__ "DMPlexRefine_Triangle"
5075 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5076 {
5077   MPI_Comm             comm = ((PetscObject) dm)->comm;
5078   PetscInt             dim  = 2;
5079   struct triangulateio in;
5080   struct triangulateio out;
5081   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5082   PetscMPIInt          rank;
5083   PetscErrorCode       ierr;
5084 
5085   PetscFunctionBegin;
5086   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5087   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5088   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5089   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5090   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5091   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5092   in.numberofpoints = vEnd - vStart;
5093   if (in.numberofpoints > 0) {
5094     PetscSection coordSection;
5095     Vec          coordinates;
5096     PetscScalar *array;
5097 
5098     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5099     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5100     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5101     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5102     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5103     for (v = vStart; v < vEnd; ++v) {
5104       const PetscInt idx = v - vStart;
5105       PetscInt       off, d;
5106 
5107       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5108       for (d = 0; d < dim; ++d) {
5109         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5110       }
5111       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5112     }
5113     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5114   }
5115   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5116   in.numberofcorners   = 3;
5117   in.numberoftriangles = cEnd - cStart;
5118   in.trianglearealist  = (double *) maxVolumes;
5119   if (in.numberoftriangles > 0) {
5120     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5121     for (c = cStart; c < cEnd; ++c) {
5122       const PetscInt idx     = c - cStart;
5123       PetscInt      *closure = PETSC_NULL;
5124       PetscInt       closureSize;
5125 
5126       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5127       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5128       for (v = 0; v < 3; ++v) {
5129         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5130       }
5131       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5132     }
5133   }
5134   /* TODO: Segment markers are missing on input */
5135 #if 0 /* Do not currently support holes */
5136   PetscReal *holeCoords;
5137   PetscInt   h, d;
5138 
5139   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5140   if (in.numberofholes > 0) {
5141     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5142     for (h = 0; h < in.numberofholes; ++h) {
5143       for (d = 0; d < dim; ++d) {
5144         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5145       }
5146     }
5147   }
5148 #endif
5149   if (!rank) {
5150     char args[32];
5151 
5152     /* Take away 'Q' for verbose output */
5153     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5154     triangulate(args, &in, &out, PETSC_NULL);
5155   }
5156   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5157   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5158   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5159   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5160   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5161 
5162   {
5163     const PetscInt numCorners  = 3;
5164     const PetscInt numCells    = out.numberoftriangles;
5165     const PetscInt numVertices = out.numberofpoints;
5166     const int     *cells       = out.trianglelist;
5167     const double  *meshCoords  = out.pointlist;
5168     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5169 
5170     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5171     /* Set labels */
5172     for (v = 0; v < numVertices; ++v) {
5173       if (out.pointmarkerlist[v]) {
5174         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5175       }
5176     }
5177     if (interpolate) {
5178       PetscInt e;
5179 
5180       for (e = 0; e < out.numberofedges; e++) {
5181         if (out.edgemarkerlist[e]) {
5182           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5183           const PetscInt *edges;
5184           PetscInt        numEdges;
5185 
5186           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5187           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5188           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5189           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5190         }
5191       }
5192     }
5193     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5194   }
5195 #if 0 /* Do not currently support holes */
5196   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5197 #endif
5198   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5199   PetscFunctionReturn(0);
5200 }
5201 #endif
5202 
5203 #if defined(PETSC_HAVE_TETGEN)
5204 #include <tetgen.h>
5205 #undef __FUNCT__
5206 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5207 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5208 {
5209   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5210   const PetscInt dim  = 3;
5211   ::tetgenio     in;
5212   ::tetgenio     out;
5213   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5214   PetscMPIInt    rank;
5215   PetscErrorCode ierr;
5216 
5217   PetscFunctionBegin;
5218   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5219   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5220   in.numberofpoints = vEnd - vStart;
5221   if (in.numberofpoints > 0) {
5222     PetscSection coordSection;
5223     Vec          coordinates;
5224     PetscScalar *array;
5225 
5226     in.pointlist       = new double[in.numberofpoints*dim];
5227     in.pointmarkerlist = new int[in.numberofpoints];
5228     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5229     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5230     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5231     for (v = vStart; v < vEnd; ++v) {
5232       const PetscInt idx = v - vStart;
5233       PetscInt       off, d;
5234 
5235       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5236       for (d = 0; d < dim; ++d) {
5237         in.pointlist[idx*dim + d] = array[off+d];
5238       }
5239       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5240     }
5241     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5242   }
5243   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5244   in.numberoffacets = fEnd - fStart;
5245   if (in.numberoffacets > 0) {
5246     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5247     in.facetmarkerlist = new int[in.numberoffacets];
5248     for (f = fStart; f < fEnd; ++f) {
5249       const PetscInt idx    = f - fStart;
5250       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5251 
5252       in.facetlist[idx].numberofpolygons = 1;
5253       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5254       in.facetlist[idx].numberofholes    = 0;
5255       in.facetlist[idx].holelist         = NULL;
5256 
5257       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5258       for (p = 0; p < numPoints*2; p += 2) {
5259         const PetscInt point = points[p];
5260         if ((point >= vStart) && (point < vEnd)) {
5261           points[numVertices++] = point;
5262         }
5263       }
5264 
5265       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5266       poly->numberofvertices = numVertices;
5267       poly->vertexlist       = new int[poly->numberofvertices];
5268       for (v = 0; v < numVertices; ++v) {
5269         const PetscInt vIdx = points[v] - vStart;
5270         poly->vertexlist[v] = vIdx;
5271       }
5272       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5273       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5274     }
5275   }
5276   if (!rank) {
5277     char args[32];
5278 
5279     /* Take away 'Q' for verbose output */
5280     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5281     ::tetrahedralize(args, &in, &out);
5282   }
5283   {
5284     const PetscInt numCorners  = 4;
5285     const PetscInt numCells    = out.numberoftetrahedra;
5286     const PetscInt numVertices = out.numberofpoints;
5287     const int     *cells       = out.tetrahedronlist;
5288     const double  *meshCoords  = out.pointlist;
5289 
5290     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5291     /* Set labels */
5292     for (v = 0; v < numVertices; ++v) {
5293       if (out.pointmarkerlist[v]) {
5294         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5295       }
5296     }
5297     if (interpolate) {
5298       PetscInt e;
5299 
5300       for (e = 0; e < out.numberofedges; e++) {
5301         if (out.edgemarkerlist[e]) {
5302           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5303           const PetscInt *edges;
5304           PetscInt        numEdges;
5305 
5306           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5307           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5308           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5309           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5310         }
5311       }
5312       for (f = 0; f < out.numberoftrifaces; f++) {
5313         if (out.trifacemarkerlist[f]) {
5314           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5315           const PetscInt *faces;
5316           PetscInt        numFaces;
5317 
5318           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5319           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5320           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5321           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5322         }
5323       }
5324     }
5325     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5326   }
5327   PetscFunctionReturn(0);
5328 }
5329 
5330 #undef __FUNCT__
5331 #define __FUNCT__ "DMPlexRefine_Tetgen"
5332 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5333 {
5334   MPI_Comm       comm = ((PetscObject) dm)->comm;
5335   const PetscInt dim  = 3;
5336   ::tetgenio     in;
5337   ::tetgenio     out;
5338   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5339   PetscMPIInt    rank;
5340   PetscErrorCode ierr;
5341 
5342   PetscFunctionBegin;
5343   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5344   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5345   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5346   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5347   in.numberofpoints = vEnd - vStart;
5348   if (in.numberofpoints > 0) {
5349     PetscSection coordSection;
5350     Vec          coordinates;
5351     PetscScalar *array;
5352 
5353     in.pointlist       = new double[in.numberofpoints*dim];
5354     in.pointmarkerlist = new int[in.numberofpoints];
5355     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5356     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5357     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5358     for (v = vStart; v < vEnd; ++v) {
5359       const PetscInt idx = v - vStart;
5360       PetscInt       off, d;
5361 
5362       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5363       for (d = 0; d < dim; ++d) {
5364         in.pointlist[idx*dim + d] = array[off+d];
5365       }
5366       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5367     }
5368     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5369   }
5370   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5371   in.numberofcorners       = 4;
5372   in.numberoftetrahedra    = cEnd - cStart;
5373   in.tetrahedronvolumelist = (double *) maxVolumes;
5374   if (in.numberoftetrahedra > 0) {
5375     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5376     for (c = cStart; c < cEnd; ++c) {
5377       const PetscInt idx     = c - cStart;
5378       PetscInt      *closure = PETSC_NULL;
5379       PetscInt       closureSize;
5380 
5381       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5382       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5383       for (v = 0; v < 4; ++v) {
5384         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5385       }
5386       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5387     }
5388   }
5389   /* TODO: Put in boundary faces with markers */
5390   if (!rank) {
5391     char args[32];
5392 
5393     /* Take away 'Q' for verbose output */
5394     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5395     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5396     ::tetrahedralize(args, &in, &out);
5397   }
5398   in.tetrahedronvolumelist = NULL;
5399 
5400   {
5401     const PetscInt numCorners  = 4;
5402     const PetscInt numCells    = out.numberoftetrahedra;
5403     const PetscInt numVertices = out.numberofpoints;
5404     const int     *cells       = out.tetrahedronlist;
5405     const double  *meshCoords  = out.pointlist;
5406     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5407 
5408     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5409     /* Set labels */
5410     for (v = 0; v < numVertices; ++v) {
5411       if (out.pointmarkerlist[v]) {
5412         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5413       }
5414     }
5415     if (interpolate) {
5416       PetscInt e, f;
5417 
5418       for (e = 0; e < out.numberofedges; e++) {
5419         if (out.edgemarkerlist[e]) {
5420           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5421           const PetscInt *edges;
5422           PetscInt        numEdges;
5423 
5424           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5425           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5426           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5427           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5428         }
5429       }
5430       for (f = 0; f < out.numberoftrifaces; f++) {
5431         if (out.trifacemarkerlist[f]) {
5432           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5433           const PetscInt *faces;
5434           PetscInt        numFaces;
5435 
5436           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5437           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5438           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5439           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5440         }
5441       }
5442     }
5443     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5444   }
5445   PetscFunctionReturn(0);
5446 }
5447 #endif
5448 
5449 #if defined(PETSC_HAVE_CTETGEN)
5450 #include "ctetgen.h"
5451 
5452 #undef __FUNCT__
5453 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5454 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5455 {
5456   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5457   const PetscInt dim  = 3;
5458   PLC           *in, *out;
5459   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5460   PetscMPIInt    rank;
5461   PetscErrorCode ierr;
5462 
5463   PetscFunctionBegin;
5464   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5465   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5466   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5467   ierr = PLCCreate(&in);CHKERRQ(ierr);
5468   ierr = PLCCreate(&out);CHKERRQ(ierr);
5469   in->numberofpoints = vEnd - vStart;
5470   if (in->numberofpoints > 0) {
5471     PetscSection coordSection;
5472     Vec          coordinates;
5473     PetscScalar *array;
5474 
5475     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5476     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5477     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5478     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5479     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5480     for (v = vStart; v < vEnd; ++v) {
5481       const PetscInt idx = v - vStart;
5482       PetscInt       off, d, m;
5483 
5484       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5485       for (d = 0; d < dim; ++d) {
5486         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5487       }
5488       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5489       in->pointmarkerlist[idx] = (int) m;
5490     }
5491     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5492   }
5493   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5494   in->numberoffacets = fEnd - fStart;
5495   if (in->numberoffacets > 0) {
5496     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5497     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5498     for (f = fStart; f < fEnd; ++f) {
5499       const PetscInt idx    = f - fStart;
5500       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5501       polygon       *poly;
5502 
5503       in->facetlist[idx].numberofpolygons = 1;
5504       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5505       in->facetlist[idx].numberofholes    = 0;
5506       in->facetlist[idx].holelist         = PETSC_NULL;
5507 
5508       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5509       for (p = 0; p < numPoints*2; p += 2) {
5510         const PetscInt point = points[p];
5511         if ((point >= vStart) && (point < vEnd)) {
5512           points[numVertices++] = point;
5513         }
5514       }
5515 
5516       poly = in->facetlist[idx].polygonlist;
5517       poly->numberofvertices = numVertices;
5518       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5519       for (v = 0; v < numVertices; ++v) {
5520         const PetscInt vIdx = points[v] - vStart;
5521         poly->vertexlist[v] = vIdx;
5522       }
5523       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5524       in->facetmarkerlist[idx] = (int) m;
5525       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5526     }
5527   }
5528   if (!rank) {
5529     TetGenOpts t;
5530 
5531     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5532     t.in        = boundary; /* Should go away */
5533     t.plc       = 1;
5534     t.quality   = 1;
5535     t.edgesout  = 1;
5536     t.zeroindex = 1;
5537     t.quiet     = 1;
5538     t.verbose   = verbose;
5539     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5540     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5541   }
5542   {
5543     const PetscInt numCorners  = 4;
5544     const PetscInt numCells    = out->numberoftetrahedra;
5545     const PetscInt numVertices = out->numberofpoints;
5546     const int     *cells       = out->tetrahedronlist;
5547     const double  *meshCoords  = out->pointlist;
5548 
5549     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5550     /* Set labels */
5551     for (v = 0; v < numVertices; ++v) {
5552       if (out->pointmarkerlist[v]) {
5553         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5554       }
5555     }
5556     if (interpolate) {
5557       PetscInt e;
5558 
5559       for (e = 0; e < out->numberofedges; e++) {
5560         if (out->edgemarkerlist[e]) {
5561           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5562           const PetscInt *edges;
5563           PetscInt        numEdges;
5564 
5565           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5566           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5567           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5568           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5569         }
5570       }
5571       for (f = 0; f < out->numberoftrifaces; f++) {
5572         if (out->trifacemarkerlist[f]) {
5573           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5574           const PetscInt *faces;
5575           PetscInt        numFaces;
5576 
5577           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5578           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5579           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5580           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5581         }
5582       }
5583     }
5584     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5585   }
5586 
5587   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5588   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5589   PetscFunctionReturn(0);
5590 }
5591 
5592 #undef __FUNCT__
5593 #define __FUNCT__ "DMPlexRefine_CTetgen"
5594 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5595 {
5596   MPI_Comm       comm = ((PetscObject) dm)->comm;
5597   const PetscInt dim  = 3;
5598   PLC           *in, *out;
5599   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5600   PetscMPIInt    rank;
5601   PetscErrorCode ierr;
5602 
5603   PetscFunctionBegin;
5604   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5605   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5606   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5607   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5608   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5609   ierr = PLCCreate(&in);CHKERRQ(ierr);
5610   ierr = PLCCreate(&out);CHKERRQ(ierr);
5611   in->numberofpoints = vEnd - vStart;
5612   if (in->numberofpoints > 0) {
5613     PetscSection coordSection;
5614     Vec          coordinates;
5615     PetscScalar *array;
5616 
5617     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5618     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5619     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5620     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5621     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5622     for (v = vStart; v < vEnd; ++v) {
5623       const PetscInt idx = v - vStart;
5624       PetscInt       off, d, m;
5625 
5626       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5627       for (d = 0; d < dim; ++d) {
5628         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5629       }
5630       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5631       in->pointmarkerlist[idx] = (int) m;
5632     }
5633     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5634   }
5635   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5636   in->numberofcorners       = 4;
5637   in->numberoftetrahedra    = cEnd - cStart;
5638   in->tetrahedronvolumelist = maxVolumes;
5639   if (in->numberoftetrahedra > 0) {
5640     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5641     for (c = cStart; c < cEnd; ++c) {
5642       const PetscInt idx     = c - cStart;
5643       PetscInt      *closure = PETSC_NULL;
5644       PetscInt       closureSize;
5645 
5646       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5647       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5648       for (v = 0; v < 4; ++v) {
5649         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5650       }
5651       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5652     }
5653   }
5654   if (!rank) {
5655     TetGenOpts t;
5656 
5657     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5658     t.in        = dm; /* Should go away */
5659     t.refine    = 1;
5660     t.varvolume = 1;
5661     t.quality   = 1;
5662     t.edgesout  = 1;
5663     t.zeroindex = 1;
5664     t.quiet     = 1;
5665     t.verbose   = verbose; /* Change this */
5666     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5667     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5668   }
5669   {
5670     const PetscInt numCorners  = 4;
5671     const PetscInt numCells    = out->numberoftetrahedra;
5672     const PetscInt numVertices = out->numberofpoints;
5673     const int     *cells       = out->tetrahedronlist;
5674     const double  *meshCoords  = out->pointlist;
5675     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5676 
5677     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5678     /* Set labels */
5679     for (v = 0; v < numVertices; ++v) {
5680       if (out->pointmarkerlist[v]) {
5681         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5682       }
5683     }
5684     if (interpolate) {
5685       PetscInt e, f;
5686 
5687       for (e = 0; e < out->numberofedges; e++) {
5688         if (out->edgemarkerlist[e]) {
5689           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5690           const PetscInt *edges;
5691           PetscInt        numEdges;
5692 
5693           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5694           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5695           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5696           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5697         }
5698       }
5699       for (f = 0; f < out->numberoftrifaces; f++) {
5700         if (out->trifacemarkerlist[f]) {
5701           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5702           const PetscInt *faces;
5703           PetscInt        numFaces;
5704 
5705           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5706           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5707           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5708           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5709         }
5710       }
5711     }
5712     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5713   }
5714   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5715   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5716   PetscFunctionReturn(0);
5717 }
5718 #endif
5719 
5720 #undef __FUNCT__
5721 #define __FUNCT__ "DMPlexGenerate"
5722 /*@C
5723   DMPlexGenerate - Generates a mesh.
5724 
5725   Not Collective
5726 
5727   Input Parameters:
5728 + boundary - The DMPlex boundary object
5729 . name - The mesh generation package name
5730 - interpolate - Flag to create intermediate mesh elements
5731 
5732   Output Parameter:
5733 . mesh - The DMPlex object
5734 
5735   Level: intermediate
5736 
5737 .keywords: mesh, elements
5738 .seealso: DMPlexCreate(), DMRefine()
5739 @*/
5740 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5741 {
5742   PetscInt       dim;
5743   char           genname[1024];
5744   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5745   PetscErrorCode ierr;
5746 
5747   PetscFunctionBegin;
5748   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5749   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5750   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5751   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5752   if (flg) {name = genname;}
5753   if (name) {
5754     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5755     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5756     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5757   }
5758   switch (dim) {
5759   case 1:
5760     if (!name || isTriangle) {
5761 #if defined(PETSC_HAVE_TRIANGLE)
5762       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5763 #else
5764       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5765 #endif
5766     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5767     break;
5768   case 2:
5769     if (!name || isCTetgen) {
5770 #if defined(PETSC_HAVE_CTETGEN)
5771       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5772 #else
5773       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5774 #endif
5775     } else if (isTetgen) {
5776 #if defined(PETSC_HAVE_TETGEN)
5777       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5778 #else
5779       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5780 #endif
5781     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5782     break;
5783   default:
5784     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5785   }
5786   PetscFunctionReturn(0);
5787 }
5788 
5789 typedef PetscInt CellRefiner;
5790 
5791 #undef __FUNCT__
5792 #define __FUNCT__ "GetDepthStart_Private"
5793 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5794 {
5795   PetscFunctionBegin;
5796   if (cStart) *cStart = 0;
5797   if (vStart) *vStart = depthSize[depth];
5798   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5799   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5800   PetscFunctionReturn(0);
5801 }
5802 
5803 #undef __FUNCT__
5804 #define __FUNCT__ "GetDepthEnd_Private"
5805 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5806 {
5807   PetscFunctionBegin;
5808   if (cEnd) *cEnd = depthSize[depth];
5809   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5810   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5811   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5812   PetscFunctionReturn(0);
5813 }
5814 
5815 #undef __FUNCT__
5816 #define __FUNCT__ "CellRefinerGetSizes"
5817 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5818 {
5819   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5820   PetscErrorCode ierr;
5821 
5822   PetscFunctionBegin;
5823   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5824   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5825   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5826   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5827   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5828   switch (refiner) {
5829   case 1:
5830     /* Simplicial 2D */
5831     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5832     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5833     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5834     break;
5835   case 3:
5836     /* Hybrid 2D */
5837     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5838     cMax = PetscMin(cEnd, cMax);
5839     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5840     fMax = PetscMin(fEnd, fMax);
5841     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5842     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 */
5843     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5844     break;
5845   case 2:
5846     /* Hex 2D */
5847     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5848     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5849     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5850     break;
5851   default:
5852     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5853   }
5854   PetscFunctionReturn(0);
5855 }
5856 
5857 #undef __FUNCT__
5858 #define __FUNCT__ "CellRefinerSetConeSizes"
5859 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5860 {
5861   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5862   PetscErrorCode ierr;
5863 
5864   PetscFunctionBegin;
5865   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5866   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5867   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5868   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5869   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5870   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5871   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5872   switch (refiner) {
5873   case 1:
5874     /* Simplicial 2D */
5875     /* All cells have 3 faces */
5876     for (c = cStart; c < cEnd; ++c) {
5877       for (r = 0; r < 4; ++r) {
5878         const PetscInt newp = (c - cStart)*4 + r;
5879 
5880         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5881       }
5882     }
5883     /* Split faces have 2 vertices and the same cells as the parent */
5884     for (f = fStart; f < fEnd; ++f) {
5885       for (r = 0; r < 2; ++r) {
5886         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5887         PetscInt       size;
5888 
5889         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5890         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5891         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5892       }
5893     }
5894     /* Interior faces have 2 vertices and 2 cells */
5895     for (c = cStart; c < cEnd; ++c) {
5896       for (r = 0; r < 3; ++r) {
5897         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5898 
5899         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5900         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5901       }
5902     }
5903     /* Old vertices have identical supports */
5904     for (v = vStart; v < vEnd; ++v) {
5905       const PetscInt newp = vStartNew + (v - vStart);
5906       PetscInt       size;
5907 
5908       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5909       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5910     }
5911     /* Face vertices have 2 + cells*2 supports */
5912     for (f = fStart; f < fEnd; ++f) {
5913       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5914       PetscInt       size;
5915 
5916       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5917       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5918     }
5919     break;
5920   case 2:
5921     /* Hex 2D */
5922     /* All cells have 4 faces */
5923     for (c = cStart; c < cEnd; ++c) {
5924       for (r = 0; r < 4; ++r) {
5925         const PetscInt newp = (c - cStart)*4 + r;
5926 
5927         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5928       }
5929     }
5930     /* Split faces have 2 vertices and the same cells as the parent */
5931     for (f = fStart; f < fEnd; ++f) {
5932       for (r = 0; r < 2; ++r) {
5933         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5934         PetscInt       size;
5935 
5936         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5937         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5938         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5939       }
5940     }
5941     /* Interior faces have 2 vertices and 2 cells */
5942     for (c = cStart; c < cEnd; ++c) {
5943       for (r = 0; r < 4; ++r) {
5944         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5945 
5946         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5947         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5948       }
5949     }
5950     /* Old vertices have identical supports */
5951     for (v = vStart; v < vEnd; ++v) {
5952       const PetscInt newp = vStartNew + (v - vStart);
5953       PetscInt       size;
5954 
5955       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5956       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5957     }
5958     /* Face vertices have 2 + cells supports */
5959     for (f = fStart; f < fEnd; ++f) {
5960       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5961       PetscInt       size;
5962 
5963       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5964       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5965     }
5966     /* Cell vertices have 4 supports */
5967     for (c = cStart; c < cEnd; ++c) {
5968       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5969 
5970       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5971     }
5972     break;
5973   case 3:
5974     /* Hybrid 2D */
5975     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5976     cMax = PetscMin(cEnd, cMax);
5977     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5978     fMax = PetscMin(fEnd, fMax);
5979     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5980     /* Interior cells have 3 faces */
5981     for (c = cStart; c < cMax; ++c) {
5982       for (r = 0; r < 4; ++r) {
5983         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5984 
5985         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5986       }
5987     }
5988     /* Hybrid cells have 4 faces */
5989     for (c = cMax; c < cEnd; ++c) {
5990       for (r = 0; r < 2; ++r) {
5991         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5992 
5993         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5994       }
5995     }
5996     /* Interior split faces have 2 vertices and the same cells as the parent */
5997     for (f = fStart; f < fMax; ++f) {
5998       for (r = 0; r < 2; ++r) {
5999         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6000         PetscInt       size;
6001 
6002         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6003         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6004         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6005       }
6006     }
6007     /* Interior cell faces have 2 vertices and 2 cells */
6008     for (c = cStart; c < cMax; ++c) {
6009       for (r = 0; r < 3; ++r) {
6010         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6011 
6012         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6013         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6014       }
6015     }
6016     /* Hybrid faces have 2 vertices and the same cells */
6017     for (f = fMax; f < fEnd; ++f) {
6018       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6019       PetscInt       size;
6020 
6021       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6022       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6023       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6024     }
6025     /* Hybrid cell faces have 2 vertices and 2 cells */
6026     for (c = cMax; c < cEnd; ++c) {
6027       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6028 
6029       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6030       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6031     }
6032     /* Old vertices have identical supports */
6033     for (v = vStart; v < vEnd; ++v) {
6034       const PetscInt newp = vStartNew + (v - vStart);
6035       PetscInt       size;
6036 
6037       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6038       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6039     }
6040     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6041     for (f = fStart; f < fMax; ++f) {
6042       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6043       const PetscInt *support;
6044       PetscInt        size, newSize = 2, s;
6045 
6046       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6047       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6048       for (s = 0; s < size; ++s) {
6049         if (support[s] >= cMax) {
6050           newSize += 1;
6051         } else {
6052           newSize += 2;
6053         }
6054       }
6055       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6056     }
6057     break;
6058   default:
6059     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6060   }
6061   PetscFunctionReturn(0);
6062 }
6063 
6064 #undef __FUNCT__
6065 #define __FUNCT__ "CellRefinerSetCones"
6066 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6067 {
6068   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;
6069   PetscInt       maxSupportSize, *supportRef;
6070   PetscErrorCode ierr;
6071 
6072   PetscFunctionBegin;
6073   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6074   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6075   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6076   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6077   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6078   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6079   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6080   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6081   switch (refiner) {
6082   case 1:
6083     /* Simplicial 2D */
6084     /*
6085      2
6086      |\
6087      | \
6088      |  \
6089      |   \
6090      | C  \
6091      |     \
6092      |      \
6093      2---1---1
6094      |\  D  / \
6095      | 2   0   \
6096      |A \ /  B  \
6097      0---0-------1
6098      */
6099     /* All cells have 3 faces */
6100     for (c = cStart; c < cEnd; ++c) {
6101       const PetscInt  newp = cStartNew + (c - cStart)*4;
6102       const PetscInt *cone, *ornt;
6103       PetscInt        coneNew[3], orntNew[3];
6104 
6105       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6106       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6107       /* A triangle */
6108       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6109       orntNew[0] = ornt[0];
6110       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6111       orntNew[1] = -2;
6112       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6113       orntNew[2] = ornt[2];
6114       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6115       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6116 #if 1
6117       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);
6118       for (p = 0; p < 3; ++p) {
6119         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);
6120       }
6121 #endif
6122       /* B triangle */
6123       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6124       orntNew[0] = ornt[0];
6125       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6126       orntNew[1] = ornt[1];
6127       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6128       orntNew[2] = -2;
6129       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6130       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6131 #if 1
6132       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);
6133       for (p = 0; p < 3; ++p) {
6134         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);
6135       }
6136 #endif
6137       /* C triangle */
6138       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6139       orntNew[0] = -2;
6140       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6141       orntNew[1] = ornt[1];
6142       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6143       orntNew[2] = ornt[2];
6144       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6145       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6146 #if 1
6147       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);
6148       for (p = 0; p < 3; ++p) {
6149         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);
6150       }
6151 #endif
6152       /* D triangle */
6153       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6154       orntNew[0] = 0;
6155       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6156       orntNew[1] = 0;
6157       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6158       orntNew[2] = 0;
6159       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6160       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6161 #if 1
6162       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);
6163       for (p = 0; p < 3; ++p) {
6164         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);
6165       }
6166 #endif
6167     }
6168     /* Split faces have 2 vertices and the same cells as the parent */
6169     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6170     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6171     for (f = fStart; f < fEnd; ++f) {
6172       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6173 
6174       for (r = 0; r < 2; ++r) {
6175         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6176         const PetscInt *cone, *support;
6177         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6178 
6179         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6180         coneNew[0] = vStartNew + (cone[0] - vStart);
6181         coneNew[1] = vStartNew + (cone[1] - vStart);
6182         coneNew[(r+1)%2] = newv;
6183         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6184 #if 1
6185         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6186         for (p = 0; p < 2; ++p) {
6187           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);
6188         }
6189 #endif
6190         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6191         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6192         for (s = 0; s < supportSize; ++s) {
6193           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6194           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6195           for (c = 0; c < coneSize; ++c) {
6196             if (cone[c] == f) {
6197               break;
6198             }
6199           }
6200           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6201         }
6202         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6203 #if 1
6204         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6205         for (p = 0; p < supportSize; ++p) {
6206           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);
6207         }
6208 #endif
6209       }
6210     }
6211     /* Interior faces have 2 vertices and 2 cells */
6212     for (c = cStart; c < cEnd; ++c) {
6213       const PetscInt *cone;
6214 
6215       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6216       for (r = 0; r < 3; ++r) {
6217         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6218         PetscInt       coneNew[2];
6219         PetscInt       supportNew[2];
6220 
6221         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6222         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6223         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6224 #if 1
6225         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6226         for (p = 0; p < 2; ++p) {
6227           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);
6228         }
6229 #endif
6230         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6231         supportNew[1] = (c - cStart)*4 + 3;
6232         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6233 #if 1
6234         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6235         for (p = 0; p < 2; ++p) {
6236           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);
6237         }
6238 #endif
6239       }
6240     }
6241     /* Old vertices have identical supports */
6242     for (v = vStart; v < vEnd; ++v) {
6243       const PetscInt  newp = vStartNew + (v - vStart);
6244       const PetscInt *support, *cone;
6245       PetscInt        size, s;
6246 
6247       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6248       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6249       for (s = 0; s < size; ++s) {
6250         PetscInt r = 0;
6251 
6252         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6253         if (cone[1] == v) r = 1;
6254         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6255       }
6256       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6257 #if 1
6258       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6259       for (p = 0; p < size; ++p) {
6260         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);
6261       }
6262 #endif
6263     }
6264     /* Face vertices have 2 + cells*2 supports */
6265     for (f = fStart; f < fEnd; ++f) {
6266       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6267       const PetscInt *cone, *support;
6268       PetscInt        size, s;
6269 
6270       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6271       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6272       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6273       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6274       for (s = 0; s < size; ++s) {
6275         PetscInt r = 0;
6276 
6277         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6278         if      (cone[1] == f) r = 1;
6279         else if (cone[2] == f) r = 2;
6280         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6281         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6282       }
6283       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6284 #if 1
6285       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6286       for (p = 0; p < 2+size*2; ++p) {
6287         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);
6288       }
6289 #endif
6290     }
6291     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6292     break;
6293   case 2:
6294     /* Hex 2D */
6295     /*
6296      3---------2---------2
6297      |         |         |
6298      |    D    2    C    |
6299      |         |         |
6300      3----3----0----1----1
6301      |         |         |
6302      |    A    0    B    |
6303      |         |         |
6304      0---------0---------1
6305      */
6306     /* All cells have 4 faces */
6307     for (c = cStart; c < cEnd; ++c) {
6308       const PetscInt  newp = (c - cStart)*4;
6309       const PetscInt *cone, *ornt;
6310       PetscInt        coneNew[4], orntNew[4];
6311 
6312       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6313       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6314       /* A quad */
6315       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6316       orntNew[0] = ornt[0];
6317       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6318       orntNew[1] = 0;
6319       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6320       orntNew[2] = -2;
6321       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6322       orntNew[3] = ornt[3];
6323       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6324       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6325 #if 1
6326       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);
6327       for (p = 0; p < 4; ++p) {
6328         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);
6329       }
6330 #endif
6331       /* B quad */
6332       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6333       orntNew[0] = ornt[0];
6334       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6335       orntNew[1] = ornt[1];
6336       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6337       orntNew[2] = 0;
6338       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6339       orntNew[3] = -2;
6340       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6341       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6342 #if 1
6343       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);
6344       for (p = 0; p < 4; ++p) {
6345         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);
6346       }
6347 #endif
6348       /* C quad */
6349       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6350       orntNew[0] = -2;
6351       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6352       orntNew[1] = ornt[1];
6353       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6354       orntNew[2] = ornt[2];
6355       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6356       orntNew[3] = 0;
6357       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6358       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6359 #if 1
6360       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);
6361       for (p = 0; p < 4; ++p) {
6362         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);
6363       }
6364 #endif
6365       /* D quad */
6366       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6367       orntNew[0] = 0;
6368       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6369       orntNew[1] = -2;
6370       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6371       orntNew[2] = ornt[2];
6372       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6373       orntNew[3] = ornt[3];
6374       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6375       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6376 #if 1
6377       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);
6378       for (p = 0; p < 4; ++p) {
6379         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);
6380       }
6381 #endif
6382     }
6383     /* Split faces have 2 vertices and the same cells as the parent */
6384     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6385     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6386     for (f = fStart; f < fEnd; ++f) {
6387       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6388 
6389       for (r = 0; r < 2; ++r) {
6390         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6391         const PetscInt *cone, *support;
6392         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6393 
6394         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6395         coneNew[0] = vStartNew + (cone[0] - vStart);
6396         coneNew[1] = vStartNew + (cone[1] - vStart);
6397         coneNew[(r+1)%2] = newv;
6398         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6399 #if 1
6400         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6401         for (p = 0; p < 2; ++p) {
6402           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);
6403         }
6404 #endif
6405         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6406         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6407         for (s = 0; s < supportSize; ++s) {
6408           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6409           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6410           for (c = 0; c < coneSize; ++c) {
6411             if (cone[c] == f) {
6412               break;
6413             }
6414           }
6415           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6416         }
6417         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6418 #if 1
6419         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6420         for (p = 0; p < supportSize; ++p) {
6421           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);
6422         }
6423 #endif
6424       }
6425     }
6426     /* Interior faces have 2 vertices and 2 cells */
6427     for (c = cStart; c < cEnd; ++c) {
6428       const PetscInt *cone;
6429       PetscInt        coneNew[2], supportNew[2];
6430 
6431       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6432       for (r = 0; r < 4; ++r) {
6433         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6434 
6435         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6436         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6437         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6438 #if 1
6439         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6440         for (p = 0; p < 2; ++p) {
6441           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);
6442         }
6443 #endif
6444         supportNew[0] = (c - cStart)*4 + r;
6445         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6446         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6447 #if 1
6448         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6449         for (p = 0; p < 2; ++p) {
6450           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);
6451         }
6452 #endif
6453       }
6454     }
6455     /* Old vertices have identical supports */
6456     for (v = vStart; v < vEnd; ++v) {
6457       const PetscInt  newp = vStartNew + (v - vStart);
6458       const PetscInt *support, *cone;
6459       PetscInt        size, s;
6460 
6461       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6462       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6463       for (s = 0; s < size; ++s) {
6464         PetscInt r = 0;
6465 
6466         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6467         if (cone[1] == v) r = 1;
6468         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6469       }
6470       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6471 #if 1
6472       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6473       for (p = 0; p < size; ++p) {
6474         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);
6475       }
6476 #endif
6477     }
6478     /* Face vertices have 2 + cells supports */
6479     for (f = fStart; f < fEnd; ++f) {
6480       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6481       const PetscInt *cone, *support;
6482       PetscInt        size, s;
6483 
6484       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6485       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6486       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6487       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6488       for (s = 0; s < size; ++s) {
6489         PetscInt r = 0;
6490 
6491         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6492         if      (cone[1] == f) r = 1;
6493         else if (cone[2] == f) r = 2;
6494         else if (cone[3] == f) r = 3;
6495         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6496       }
6497       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6498 #if 1
6499       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6500       for (p = 0; p < 2+size; ++p) {
6501         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);
6502       }
6503 #endif
6504     }
6505     /* Cell vertices have 4 supports */
6506     for (c = cStart; c < cEnd; ++c) {
6507       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6508       PetscInt       supportNew[4];
6509 
6510       for (r = 0; r < 4; ++r) {
6511         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6512       }
6513       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6514     }
6515     break;
6516   case 3:
6517     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6518     cMax = PetscMin(cEnd, cMax);
6519     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6520     fMax = PetscMin(fEnd, fMax);
6521     /* Interior cells have 3 faces */
6522     for (c = cStart; c < cMax; ++c) {
6523       const PetscInt  newp = cStartNew + (c - cStart)*4;
6524       const PetscInt *cone, *ornt;
6525       PetscInt        coneNew[3], orntNew[3];
6526 
6527       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6528       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6529       /* A triangle */
6530       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6531       orntNew[0] = ornt[0];
6532       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6533       orntNew[1] = -2;
6534       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6535       orntNew[2] = ornt[2];
6536       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6537       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6538 #if 1
6539       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);
6540       for (p = 0; p < 3; ++p) {
6541         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);
6542       }
6543 #endif
6544       /* B triangle */
6545       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6546       orntNew[0] = ornt[0];
6547       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6548       orntNew[1] = ornt[1];
6549       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6550       orntNew[2] = -2;
6551       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6552       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6553 #if 1
6554       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);
6555       for (p = 0; p < 3; ++p) {
6556         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);
6557       }
6558 #endif
6559       /* C triangle */
6560       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6561       orntNew[0] = -2;
6562       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6563       orntNew[1] = ornt[1];
6564       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6565       orntNew[2] = ornt[2];
6566       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6567       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6568 #if 1
6569       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);
6570       for (p = 0; p < 3; ++p) {
6571         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);
6572       }
6573 #endif
6574       /* D triangle */
6575       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6576       orntNew[0] = 0;
6577       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6578       orntNew[1] = 0;
6579       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6580       orntNew[2] = 0;
6581       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6582       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6583 #if 1
6584       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);
6585       for (p = 0; p < 3; ++p) {
6586         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);
6587       }
6588 #endif
6589     }
6590     /*
6591      2----3----3
6592      |         |
6593      |    B    |
6594      |         |
6595      0----4--- 1
6596      |         |
6597      |    A    |
6598      |         |
6599      0----2----1
6600      */
6601     /* Hybrid cells have 4 faces */
6602     for (c = cMax; c < cEnd; ++c) {
6603       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6604       const PetscInt *cone, *ornt;
6605       PetscInt        coneNew[4], orntNew[4];
6606 
6607       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6608       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6609       /* A quad */
6610       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6611       orntNew[0] = ornt[0];
6612       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6613       orntNew[1] = ornt[1];
6614       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6615       orntNew[2] = 0;
6616       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6617       orntNew[3] = 0;
6618       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6619       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6620 #if 1
6621       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);
6622       for (p = 0; p < 4; ++p) {
6623         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);
6624       }
6625 #endif
6626       /* B quad */
6627       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6628       orntNew[0] = ornt[0];
6629       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6630       orntNew[1] = ornt[1];
6631       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6632       orntNew[2] = 0;
6633       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6634       orntNew[3] = 0;
6635       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6636       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6637 #if 1
6638       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6639       for (p = 0; p < 4; ++p) {
6640         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);
6641       }
6642 #endif
6643     }
6644     /* Interior split faces have 2 vertices and the same cells as the parent */
6645     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6646     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6647     for (f = fStart; f < fMax; ++f) {
6648       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6649 
6650       for (r = 0; r < 2; ++r) {
6651         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6652         const PetscInt *cone, *support;
6653         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6654 
6655         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6656         coneNew[0] = vStartNew + (cone[0] - vStart);
6657         coneNew[1] = vStartNew + (cone[1] - vStart);
6658         coneNew[(r+1)%2] = newv;
6659         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6660 #if 1
6661         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6662         for (p = 0; p < 2; ++p) {
6663           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);
6664         }
6665 #endif
6666         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6667         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6668         for (s = 0; s < supportSize; ++s) {
6669           if (support[s] >= cMax) {
6670             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6671           } else {
6672             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6673             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6674             for (c = 0; c < coneSize; ++c) {
6675               if (cone[c] == f) {
6676                 break;
6677               }
6678             }
6679             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6680           }
6681         }
6682         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6683 #if 1
6684         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6685         for (p = 0; p < supportSize; ++p) {
6686           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);
6687         }
6688 #endif
6689       }
6690     }
6691     /* Interior cell faces have 2 vertices and 2 cells */
6692     for (c = cStart; c < cMax; ++c) {
6693       const PetscInt *cone;
6694 
6695       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6696       for (r = 0; r < 3; ++r) {
6697         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6698         PetscInt       coneNew[2];
6699         PetscInt       supportNew[2];
6700 
6701         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6702         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6703         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6704 #if 1
6705         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6706         for (p = 0; p < 2; ++p) {
6707           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);
6708         }
6709 #endif
6710         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6711         supportNew[1] = (c - cStart)*4 + 3;
6712         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6713 #if 1
6714         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6715         for (p = 0; p < 2; ++p) {
6716           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);
6717         }
6718 #endif
6719       }
6720     }
6721     /* Interior hybrid faces have 2 vertices and the same cells */
6722     for (f = fMax; f < fEnd; ++f) {
6723       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6724       const PetscInt *cone;
6725       const PetscInt *support;
6726       PetscInt        coneNew[2];
6727       PetscInt        supportNew[2];
6728       PetscInt        size, s, r;
6729 
6730       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6731       coneNew[0] = vStartNew + (cone[0] - vStart);
6732       coneNew[1] = vStartNew + (cone[1] - vStart);
6733       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6734 #if 1
6735       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6736       for (p = 0; p < 2; ++p) {
6737         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);
6738       }
6739 #endif
6740       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6741       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6742       for (s = 0; s < size; ++s) {
6743         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6744         for (r = 0; r < 2; ++r) {
6745           if (cone[r+2] == f) break;
6746         }
6747         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6748       }
6749       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6750 #if 1
6751       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6752       for (p = 0; p < size; ++p) {
6753         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);
6754       }
6755 #endif
6756     }
6757     /* Cell hybrid faces have 2 vertices and 2 cells */
6758     for (c = cMax; c < cEnd; ++c) {
6759       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6760       const PetscInt *cone;
6761       PetscInt        coneNew[2];
6762       PetscInt        supportNew[2];
6763 
6764       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6765       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6766       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6767       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6768 #if 1
6769       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6770       for (p = 0; p < 2; ++p) {
6771         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);
6772       }
6773 #endif
6774       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6775       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6776       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6777 #if 1
6778       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6779       for (p = 0; p < 2; ++p) {
6780         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);
6781       }
6782 #endif
6783     }
6784     /* Old vertices have identical supports */
6785     for (v = vStart; v < vEnd; ++v) {
6786       const PetscInt  newp = vStartNew + (v - vStart);
6787       const PetscInt *support, *cone;
6788       PetscInt        size, s;
6789 
6790       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6791       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6792       for (s = 0; s < size; ++s) {
6793         if (support[s] >= fMax) {
6794           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6795         } else {
6796           PetscInt r = 0;
6797 
6798           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6799           if (cone[1] == v) r = 1;
6800           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6801         }
6802       }
6803       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6804 #if 1
6805       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6806       for (p = 0; p < size; ++p) {
6807         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);
6808       }
6809 #endif
6810     }
6811     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6812     for (f = fStart; f < fMax; ++f) {
6813       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6814       const PetscInt *cone, *support;
6815       PetscInt        size, newSize = 2, s;
6816 
6817       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6818       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6819       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6820       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6821       for (s = 0; s < size; ++s) {
6822         PetscInt r = 0;
6823 
6824         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6825         if (support[s] >= cMax) {
6826           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6827           newSize += 1;
6828         } else {
6829           if      (cone[1] == f) r = 1;
6830           else if (cone[2] == f) r = 2;
6831           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6832           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6833           newSize += 2;
6834         }
6835       }
6836       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6837 #if 1
6838       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6839       for (p = 0; p < newSize; ++p) {
6840         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);
6841       }
6842 #endif
6843     }
6844     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6845     break;
6846   default:
6847     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6848   }
6849   PetscFunctionReturn(0);
6850 }
6851 
6852 #undef __FUNCT__
6853 #define __FUNCT__ "CellRefinerSetCoordinates"
6854 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6855 {
6856   PetscSection   coordSection, coordSectionNew;
6857   Vec            coordinates, coordinatesNew;
6858   PetscScalar   *coords, *coordsNew;
6859   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6860   PetscErrorCode ierr;
6861 
6862   PetscFunctionBegin;
6863   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6864   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6865   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6866   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6867   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6868   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6869   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6870   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6871   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6872   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6873   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6874   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6875   if (fMax < 0) fMax = fEnd;
6876   switch (refiner) {
6877   case 1:
6878   case 2:
6879   case 3:
6880     /* Simplicial and Hex 2D */
6881     /* All vertices have the dim coordinates */
6882     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6883       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6884       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6885     }
6886     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6887     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6888     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6889     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6890     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6891     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6892     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6893     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6894     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6895     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6896     /* Old vertices have the same coordinates */
6897     for (v = vStart; v < vEnd; ++v) {
6898       const PetscInt newv = vStartNew + (v - vStart);
6899       PetscInt       off, offnew, d;
6900 
6901       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6902       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6903       for (d = 0; d < dim; ++d) {
6904         coordsNew[offnew+d] = coords[off+d];
6905       }
6906     }
6907     /* Face vertices have the average of endpoint coordinates */
6908     for (f = fStart; f < fMax; ++f) {
6909       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6910       const PetscInt *cone;
6911       PetscInt        coneSize, offA, offB, offnew, d;
6912 
6913       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6914       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6915       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6916       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6917       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6918       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6919       for (d = 0; d < dim; ++d) {
6920         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6921       }
6922     }
6923     /* Just Hex 2D */
6924     if (refiner == 2) {
6925       /* Cell vertices have the average of corner coordinates */
6926       for (c = cStart; c < cEnd; ++c) {
6927         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6928         PetscInt      *cone = PETSC_NULL;
6929         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6930 
6931         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6932         for (p = 0; p < closureSize*2; p += 2) {
6933           const PetscInt point = cone[p];
6934           if ((point >= vStart) && (point < vEnd)) {
6935             cone[coneSize++] = point;
6936           }
6937         }
6938         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6939         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6940         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6941         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6942         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6943         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6944         for (d = 0; d < dim; ++d) {
6945           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6946         }
6947         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6948       }
6949     }
6950     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6951     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6952     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6953     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6954     break;
6955   default:
6956     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6957   }
6958   PetscFunctionReturn(0);
6959 }
6960 
6961 #undef __FUNCT__
6962 #define __FUNCT__ "DMPlexCreateProcessSF"
6963 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6964 {
6965   PetscInt           numRoots, numLeaves, l;
6966   const PetscInt    *localPoints;
6967   const PetscSFNode *remotePoints;
6968   PetscInt          *localPointsNew;
6969   PetscSFNode       *remotePointsNew;
6970   PetscInt          *ranks, *ranksNew;
6971   PetscErrorCode     ierr;
6972 
6973   PetscFunctionBegin;
6974   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6975   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6976   for (l = 0; l < numLeaves; ++l) {
6977     ranks[l] = remotePoints[l].rank;
6978   }
6979   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6980   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6981   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6982   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6983   for (l = 0; l < numLeaves; ++l) {
6984     ranksNew[l]              = ranks[l];
6985     localPointsNew[l]        = l;
6986     remotePointsNew[l].index = 0;
6987     remotePointsNew[l].rank  = ranksNew[l];
6988   }
6989   ierr = PetscFree(ranks);CHKERRQ(ierr);
6990   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6991   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6992   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6993   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6994   PetscFunctionReturn(0);
6995 }
6996 
6997 #undef __FUNCT__
6998 #define __FUNCT__ "CellRefinerCreateSF"
6999 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7000 {
7001   PetscSF            sf, sfNew, sfProcess;
7002   IS                 processRanks;
7003   MPI_Datatype       depthType;
7004   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7005   const PetscInt    *localPoints, *neighbors;
7006   const PetscSFNode *remotePoints;
7007   PetscInt          *localPointsNew;
7008   PetscSFNode       *remotePointsNew;
7009   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7010   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7011   PetscErrorCode     ierr;
7012 
7013   PetscFunctionBegin;
7014   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7015   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7016   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7017   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7018   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7019   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7020   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7021   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7022   switch (refiner) {
7023   case 3:
7024     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7025     cMax = PetscMin(cEnd, cMax);
7026     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7027     fMax = PetscMin(fEnd, fMax);
7028   }
7029   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7030   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7031   /* Caculate size of new SF */
7032   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7033   if (numRoots < 0) PetscFunctionReturn(0);
7034   for (l = 0; l < numLeaves; ++l) {
7035     const PetscInt p = localPoints[l];
7036 
7037     switch (refiner) {
7038     case 1:
7039       /* Simplicial 2D */
7040       if ((p >= vStart) && (p < vEnd)) {
7041         /* Old vertices stay the same */
7042         ++numLeavesNew;
7043       } else if ((p >= fStart) && (p < fEnd)) {
7044         /* Old faces add new faces and vertex */
7045         numLeavesNew += 1 + 2;
7046       } else if ((p >= cStart) && (p < cEnd)) {
7047         /* Old cells add new cells and interior faces */
7048         numLeavesNew += 4 + 3;
7049       }
7050       break;
7051     case 2:
7052       /* Hex 2D */
7053       if ((p >= vStart) && (p < vEnd)) {
7054         /* Old vertices stay the same */
7055         ++numLeavesNew;
7056       } else if ((p >= fStart) && (p < fEnd)) {
7057         /* Old faces add new faces and vertex */
7058         numLeavesNew += 1 + 2;
7059       } else if ((p >= cStart) && (p < cEnd)) {
7060         /* Old cells add new cells and interior faces */
7061         numLeavesNew += 4 + 4;
7062       }
7063       break;
7064     default:
7065       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7066     }
7067   }
7068   /* Communicate depthSizes for each remote rank */
7069   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7070   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7071   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7072   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);
7073   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7074   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7075   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7076   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7077   for (n = 0; n < numNeighbors; ++n) {
7078     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7079   }
7080   depthSizeOld[depth]   = cMax;
7081   depthSizeOld[0]       = vMax;
7082   depthSizeOld[depth-1] = fMax;
7083   depthSizeOld[1]       = eMax;
7084   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7085   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7086   depthSizeOld[depth]   = cEnd - cStart;
7087   depthSizeOld[0]       = vEnd - vStart;
7088   depthSizeOld[depth-1] = fEnd - fStart;
7089   depthSizeOld[1]       = eEnd - eStart;
7090   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7091   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7092   for (n = 0; n < numNeighbors; ++n) {
7093     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7094   }
7095   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7096   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7097   /* Calculate new point SF */
7098   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7099   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7100   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7101   for (l = 0, m = 0; l < numLeaves; ++l) {
7102     PetscInt    p     = localPoints[l];
7103     PetscInt    rp    = remotePoints[l].index, n;
7104     PetscMPIInt rrank = remotePoints[l].rank;
7105 
7106     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7107     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7108     switch (refiner) {
7109     case 1:
7110       /* Simplicial 2D */
7111       if ((p >= vStart) && (p < vEnd)) {
7112         /* Old vertices stay the same */
7113         localPointsNew[m]        = vStartNew     + (p  - vStart);
7114         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7115         remotePointsNew[m].rank  = rrank;
7116         ++m;
7117       } else if ((p >= fStart) && (p < fEnd)) {
7118         /* Old faces add new faces and vertex */
7119         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7120         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7121         remotePointsNew[m].rank  = rrank;
7122         ++m;
7123         for (r = 0; r < 2; ++r, ++m) {
7124           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7125           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7126           remotePointsNew[m].rank  = rrank;
7127         }
7128       } else if ((p >= cStart) && (p < cEnd)) {
7129         /* Old cells add new cells and interior faces */
7130         for (r = 0; r < 4; ++r, ++m) {
7131           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7132           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7133           remotePointsNew[m].rank  = rrank;
7134         }
7135         for (r = 0; r < 3; ++r, ++m) {
7136           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7137           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7138           remotePointsNew[m].rank  = rrank;
7139         }
7140       }
7141       break;
7142     case 2:
7143       /* Hex 2D */
7144       if ((p >= vStart) && (p < vEnd)) {
7145         /* Old vertices stay the same */
7146         localPointsNew[m]        = vStartNew     + (p  - vStart);
7147         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7148         remotePointsNew[m].rank  = rrank;
7149         ++m;
7150       } else if ((p >= fStart) && (p < fEnd)) {
7151         /* Old faces add new faces and vertex */
7152         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7153         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7154         remotePointsNew[m].rank  = rrank;
7155         ++m;
7156         for (r = 0; r < 2; ++r, ++m) {
7157           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7158           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7159           remotePointsNew[m].rank  = rrank;
7160         }
7161       } else if ((p >= cStart) && (p < cEnd)) {
7162         /* Old cells add new cells and interior faces */
7163         for (r = 0; r < 4; ++r, ++m) {
7164           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7165           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7166           remotePointsNew[m].rank  = rrank;
7167         }
7168         for (r = 0; r < 4; ++r, ++m) {
7169           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7170           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7171           remotePointsNew[m].rank  = rrank;
7172         }
7173       }
7174       break;
7175     case 3:
7176       /* Hybrid simplicial 2D */
7177       if ((p >= vStart) && (p < vEnd)) {
7178         /* Old vertices stay the same */
7179         localPointsNew[m]        = vStartNew     + (p  - vStart);
7180         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7181         remotePointsNew[m].rank  = rrank;
7182         ++m;
7183       } else if ((p >= fStart) && (p < fMax)) {
7184         /* Old interior faces add new faces and vertex */
7185         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7186         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7187         remotePointsNew[m].rank  = rrank;
7188         ++m;
7189         for (r = 0; r < 2; ++r, ++m) {
7190           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7191           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7192           remotePointsNew[m].rank  = rrank;
7193         }
7194       } else if ((p >= fMax) && (p < fEnd)) {
7195         /* Old hybrid faces stay the same */
7196         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7197         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7198         remotePointsNew[m].rank  = rrank;
7199         ++m;
7200       } else if ((p >= cStart) && (p < cMax)) {
7201         /* Old interior cells add new cells and interior faces */
7202         for (r = 0; r < 4; ++r, ++m) {
7203           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7204           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7205           remotePointsNew[m].rank  = rrank;
7206         }
7207         for (r = 0; r < 3; ++r, ++m) {
7208           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7209           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7210           remotePointsNew[m].rank  = rrank;
7211         }
7212       } else if ((p >= cStart) && (p < cMax)) {
7213         /* Old hybrid cells add new cells and hybrid face */
7214         for (r = 0; r < 2; ++r, ++m) {
7215           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7216           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7217           remotePointsNew[m].rank  = rrank;
7218         }
7219         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7220         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]);
7221         remotePointsNew[m].rank  = rrank;
7222         ++m;
7223       }
7224       break;
7225     default:
7226       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7227     }
7228   }
7229   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7230   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7231   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7232   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7233   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7234   PetscFunctionReturn(0);
7235 }
7236 
7237 #undef __FUNCT__
7238 #define __FUNCT__ "CellRefinerCreateLabels"
7239 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7240 {
7241   PetscInt       numLabels, l;
7242   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7243   PetscErrorCode ierr;
7244 
7245   PetscFunctionBegin;
7246   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7247   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7248   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7249   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7250   cStartNew = 0;
7251   vStartNew = depthSize[2];
7252   fStartNew = depthSize[2] + depthSize[0];
7253   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7254   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7255   switch (refiner) {
7256   case 3:
7257     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7258     cMax = PetscMin(cEnd, cMax);
7259     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7260     fMax = PetscMin(fEnd, fMax);
7261   }
7262   for (l = 0; l < numLabels; ++l) {
7263     DMLabel         label, labelNew;
7264     const char     *lname;
7265     PetscBool       isDepth;
7266     IS              valueIS;
7267     const PetscInt *values;
7268     PetscInt        numValues, val;
7269 
7270     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7271     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7272     if (isDepth) continue;
7273     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7274     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7275     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7276     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7277     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7278     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7279     for (val = 0; val < numValues; ++val) {
7280       IS              pointIS;
7281       const PetscInt *points;
7282       PetscInt        numPoints, n;
7283 
7284       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7285       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7286       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7287       for (n = 0; n < numPoints; ++n) {
7288         const PetscInt p = points[n];
7289         switch (refiner) {
7290         case 1:
7291           /* Simplicial 2D */
7292           if ((p >= vStart) && (p < vEnd)) {
7293             /* Old vertices stay the same */
7294             newp = vStartNew + (p - vStart);
7295             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7296           } else if ((p >= fStart) && (p < fEnd)) {
7297             /* Old faces add new faces and vertex */
7298             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7299             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7300             for (r = 0; r < 2; ++r) {
7301               newp = fStartNew + (p - fStart)*2 + r;
7302               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7303             }
7304           } else if ((p >= cStart) && (p < cEnd)) {
7305             /* Old cells add new cells and interior faces */
7306             for (r = 0; r < 4; ++r) {
7307               newp = cStartNew + (p - cStart)*4 + r;
7308               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7309             }
7310             for (r = 0; r < 3; ++r) {
7311               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7312               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7313             }
7314           }
7315           break;
7316         case 2:
7317           /* Hex 2D */
7318           if ((p >= vStart) && (p < vEnd)) {
7319             /* Old vertices stay the same */
7320             newp = vStartNew + (p - vStart);
7321             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7322           } else if ((p >= fStart) && (p < fEnd)) {
7323             /* Old faces add new faces and vertex */
7324             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7325             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7326             for (r = 0; r < 2; ++r) {
7327               newp = fStartNew + (p - fStart)*2 + r;
7328               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7329             }
7330           } else if ((p >= cStart) && (p < cEnd)) {
7331             /* Old cells add new cells and interior faces and vertex */
7332             for (r = 0; r < 4; ++r) {
7333               newp = cStartNew + (p - cStart)*4 + r;
7334               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7335             }
7336             for (r = 0; r < 4; ++r) {
7337               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7338               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7339             }
7340             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7341             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7342           }
7343           break;
7344         case 3:
7345           /* Hybrid simplicial 2D */
7346           if ((p >= vStart) && (p < vEnd)) {
7347             /* Old vertices stay the same */
7348             newp = vStartNew + (p - vStart);
7349             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7350           } else if ((p >= fStart) && (p < fMax)) {
7351             /* Old interior faces add new faces and vertex */
7352             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7353             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7354             for (r = 0; r < 2; ++r) {
7355               newp = fStartNew + (p - fStart)*2 + r;
7356               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7357             }
7358           } else if ((p >= fMax) && (p < fEnd)) {
7359             /* Old hybrid faces stay the same */
7360             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7361             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7362           } else if ((p >= cStart) && (p < cMax)) {
7363             /* Old interior cells add new cells and interior faces */
7364             for (r = 0; r < 4; ++r) {
7365               newp = cStartNew + (p - cStart)*4 + r;
7366               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7367             }
7368             for (r = 0; r < 3; ++r) {
7369               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7370               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7371             }
7372           } else if ((p >= cMax) && (p < cEnd)) {
7373             /* Old hybrid cells add new cells and hybrid face */
7374             for (r = 0; r < 2; ++r) {
7375               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7376               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7377             }
7378             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7379             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7380           }
7381           break;
7382         default:
7383           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7384         }
7385       }
7386       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7387       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7388     }
7389     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7390     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7391     if (0) {
7392       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7393       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7394       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7395     }
7396   }
7397   PetscFunctionReturn(0);
7398 }
7399 
7400 #undef __FUNCT__
7401 #define __FUNCT__ "DMPlexRefine_Uniform"
7402 /* This will only work for interpolated meshes */
7403 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7404 {
7405   DM              rdm;
7406   PetscInt       *depthSize;
7407   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
7408   PetscErrorCode  ierr;
7409 
7410   PetscFunctionBegin;
7411   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7412   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7413   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7414   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7415   /* Calculate number of new points of each depth */
7416   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7417   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7418   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7419   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7420   /* Step 1: Set chart */
7421   for (d = 0; d <= depth; ++d) {
7422     pEnd += depthSize[d];
7423   }
7424   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7425   /* Step 2: Set cone/support sizes */
7426   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7427   /* Step 3: Setup refined DM */
7428   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7429   /* Step 4: Set cones and supports */
7430   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7431   /* Step 5: Stratify */
7432   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7433   /* Step 6: Set coordinates for vertices */
7434   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7435   /* Step 7: Create pointSF */
7436   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7437   /* Step 8: Create labels */
7438   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7439   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7440 
7441   *dmRefined = rdm;
7442 #if 0
7443   DM_Plex *mesh = (DM_Plex *) dm->data;
7444   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7445   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7446 
7447   PetscFunctionBegin;
7448   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7449   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7450   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7451   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7452   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7453 
7454   /* Count number of new cells which are normal and extra */
7455   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7456   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7457   for (c = cStart; c < cEnd2; ++c) {
7458     PetscInt n;
7459     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7460     newNumCellsNormal += n;
7461   }
7462   for (c = cEnd2; c < cEnd; ++c) {
7463     PetscInt n;
7464     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7465     newNumCellsExtra += n;
7466   }
7467   newNumCells = newNumCellsNormal + newNumCellsExtra;
7468   /* Count number of new vertices which are normal and extra */
7469   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7470   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7471   for (c = cStart; c < cEnd; ++c) {
7472     PetscInt *closure = PETSC_NULL;
7473     PetscInt  closureSize, numCorners = 0, p;
7474 
7475     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7476     for (p = 0; p < closureSize*2; p += 2) {
7477       const PetscInt point = closure[p];
7478       if ((point >= vStart) && (point < vEnd)) {
7479         closure[numCorners++] = point;
7480       }
7481     }
7482     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7483     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7484   }
7485   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7486   for (c = cEnd2; c < cEnd; ++c) {
7487     PetscInt *closure = PETSC_NULL;
7488     PetscInt  closureSize, numCorners = 0, p;
7489 
7490     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7491     for (p = 0; p < closureSize*2; p += 2) {
7492       const PetscInt point = closure[p];
7493       if ((point >= vStart) && (point < vEnd)) {
7494         closure[numCorners++] = point;
7495       }
7496     }
7497     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7498     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7499   } /* for */
7500   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7501   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
7502 
7503 #if 1
7504   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
7505   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
7506   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7507   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7508   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7509   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7510   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7511   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7512   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7513   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7514   ierr = PetscSynchronizedFlush(comm);
7515 #endif
7516 
7517   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7518   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7519   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7520   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7521   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7522   /* Set cone and support sizes for new normal cells */
7523   PetscInt newCell = 0;
7524   for (c = cStart; c < cEnd2; ++c) {
7525     PetscInt coneSize, n, i;
7526 
7527     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7528     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7529     for (i = 0; i < n; ++i, ++newCell) {
7530       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7531     }
7532 
7533     PetscInt *closure = PETSC_NULL;
7534     PetscInt  closureSize, numCorners = 0, p;
7535 
7536     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7537     for (p = 0; p < closureSize*2; p += 2) {
7538       const PetscInt point = closure[p];
7539       if ((point >= vStart) && (point < vEnd)) {
7540         closure[numCorners++] = point;
7541       }
7542     }
7543     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7544     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7545   }
7546 
7547   /* Reset current new cell value and loop over censored cells. */
7548   curNewCell = _orderNewMesh->cellsCensored().min();
7549   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7550   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7551     /* Set new cone and support sizes */
7552     cV.clear();
7553     sieve->cone(*c_iter, cV);
7554     const point_type* cone = cV.getPoints();
7555     const int coneSize = cV.getSize();
7556 
7557     const point_type* newCells;
7558     int numNewCells = 0;
7559     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7560 
7561     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7562       newSieve->setConeSize(curNewCell, coneSize);
7563       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7564         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7565       } /* for */
7566     } /* for */
7567   } /* for */
7568   newSieve->allocate();
7569 
7570   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7571 
7572   /* Create refined cells in new sieve. */
7573   curNewCell = _orderNewMesh->cellsNormal().min();
7574   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7575   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7576     cV.clear();
7577     sieve->cone(*c_iter, cV);
7578     const point_type *cone = cV.getPoints();
7579     const int coneSize = cV.getSize();
7580 
7581     const point_type* newCells;
7582     int numNewCells = 0;
7583     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7584 
7585     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7586       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7587     } /* for */
7588   } /* for */
7589   curNewCell = _orderNewMesh->cellsCensored().min();
7590   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7591   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7592     cV.clear();
7593     sieve->cone(*c_iter, cV);
7594     const point_type *cone = cV.getPoints();
7595     const int coneSize = cV.getSize();
7596 
7597     const point_type* newCells;
7598     int numNewCells = 0;
7599     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7600 
7601     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7602       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7603     } /* for */
7604   } /* for */
7605   newSieve->symmetrize();
7606 
7607   /* Set coordinates in refined mesh. */
7608   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7609   assert(!coordinates.isNull());
7610   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7611   assert(!newCoordinates.isNull());
7612 
7613   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7614   assert(vertices->size() > 0);
7615   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7616   assert(spaceDim > 0);
7617   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7618 
7619   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7620   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7621     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7622   } /* for */
7623   newCoordinates->allocatePoint();
7624 
7625   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7626   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7627     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7628     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7629   } /* for */
7630   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7631   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7632     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7633     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7634   } /* for */
7635 
7636   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7637 
7638   /* Create sensored depth */
7639   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7640   assert(!censoredLabel.isNull());
7641 
7642   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7643 
7644   newSieve->roots(depthVisitor);
7645   while (depthVisitor.isModified()) {
7646     /* FIX: Avoid the copy here somehow by fixing the traversal */
7647     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7648 
7649     depthVisitor.clear();
7650     newSieve->support(modifiedPoints, depthVisitor);
7651   } /* while */
7652   /* Stratify refined mesh */
7653   /* Calculate new point SF */
7654   _calcNewOverlap(newMesh, mesh, refiner);
7655   /* Calculate new labels */
7656   _createLabels(newMesh, mesh, refiner);
7657 #endif
7658   PetscFunctionReturn(0);
7659 }
7660 
7661 #undef __FUNCT__
7662 #define __FUNCT__ "DMPlexSetRefinementUniform"
7663 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7664 {
7665   DM_Plex *mesh = (DM_Plex *) dm->data;
7666 
7667   PetscFunctionBegin;
7668   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7669   mesh->refinementUniform = refinementUniform;
7670   PetscFunctionReturn(0);
7671 }
7672 
7673 #undef __FUNCT__
7674 #define __FUNCT__ "DMPlexGetRefinementUniform"
7675 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7676 {
7677   DM_Plex *mesh = (DM_Plex *) dm->data;
7678 
7679   PetscFunctionBegin;
7680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7681   PetscValidPointer(refinementUniform,  2);
7682   *refinementUniform = mesh->refinementUniform;
7683   PetscFunctionReturn(0);
7684 }
7685 
7686 #undef __FUNCT__
7687 #define __FUNCT__ "DMPlexSetRefinementLimit"
7688 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7689 {
7690   DM_Plex *mesh = (DM_Plex *) dm->data;
7691 
7692   PetscFunctionBegin;
7693   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7694   mesh->refinementLimit = refinementLimit;
7695   PetscFunctionReturn(0);
7696 }
7697 
7698 #undef __FUNCT__
7699 #define __FUNCT__ "DMPlexGetRefinementLimit"
7700 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7701 {
7702   DM_Plex *mesh = (DM_Plex *) dm->data;
7703 
7704   PetscFunctionBegin;
7705   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7706   PetscValidPointer(refinementLimit,  2);
7707   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7708   *refinementLimit = mesh->refinementLimit;
7709   PetscFunctionReturn(0);
7710 }
7711 
7712 #undef __FUNCT__
7713 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7714 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7715 {
7716   PetscInt       dim, cStart, coneSize, cMax;
7717   PetscErrorCode ierr;
7718 
7719   PetscFunctionBegin;
7720   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7721   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7722   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7723   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7724   switch (dim) {
7725   case 2:
7726     switch (coneSize) {
7727     case 3:
7728       if (cMax >= 0) {
7729         *cellRefiner = 3; /* Hybrid */
7730       } else {
7731         *cellRefiner = 1; /* Triangular */
7732       }
7733       break;
7734     case 4:
7735       if (cMax >= 0) {
7736         *cellRefiner = 4; /* Hybrid */
7737       } else {
7738         *cellRefiner = 2; /* Quadrilateral */
7739       }
7740       break;
7741     default:
7742       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7743     }
7744     break;
7745   default:
7746     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7747   }
7748   PetscFunctionReturn(0);
7749 }
7750 
7751 #undef __FUNCT__
7752 #define __FUNCT__ "DMRefine_Plex"
7753 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7754 {
7755   PetscReal      refinementLimit;
7756   PetscInt       dim, cStart, cEnd;
7757   char           genname[1024], *name = PETSC_NULL;
7758   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7759   PetscErrorCode ierr;
7760 
7761   PetscFunctionBegin;
7762   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7763   if (isUniform) {
7764     CellRefiner cellRefiner;
7765 
7766     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7767     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7768     PetscFunctionReturn(0);
7769   }
7770   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7771   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7772   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7773   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7774   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7775   if (flg) {name = genname;}
7776   if (name) {
7777     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7778     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7779     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7780   }
7781   switch (dim) {
7782   case 2:
7783     if (!name || isTriangle) {
7784 #if defined(PETSC_HAVE_TRIANGLE)
7785       double  *maxVolumes;
7786       PetscInt c;
7787 
7788       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7789       for (c = 0; c < cEnd-cStart; ++c) {
7790         maxVolumes[c] = refinementLimit;
7791       }
7792       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7793 #else
7794       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7795 #endif
7796     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7797     break;
7798   case 3:
7799     if (!name || isCTetgen) {
7800 #if defined(PETSC_HAVE_CTETGEN)
7801       PetscReal *maxVolumes;
7802       PetscInt   c;
7803 
7804       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7805       for (c = 0; c < cEnd-cStart; ++c) {
7806         maxVolumes[c] = refinementLimit;
7807       }
7808       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7809 #else
7810       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7811 #endif
7812     } else if (isTetgen) {
7813 #if defined(PETSC_HAVE_TETGEN)
7814       double  *maxVolumes;
7815       PetscInt c;
7816 
7817       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7818       for (c = 0; c < cEnd-cStart; ++c) {
7819         maxVolumes[c] = refinementLimit;
7820       }
7821       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7822 #else
7823       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7824 #endif
7825     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7826     break;
7827   default:
7828     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7829   }
7830   PetscFunctionReturn(0);
7831 }
7832 
7833 #undef __FUNCT__
7834 #define __FUNCT__ "DMPlexGetDepth"
7835 /*@
7836   DMPlexGetDepth - get the number of strata
7837 
7838   Not Collective
7839 
7840   Input Parameters:
7841 . dm           - The DMPlex object
7842 
7843   Output Parameters:
7844 . depth - number of strata
7845 
7846   Level: developer
7847 
7848   Notes:
7849   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7850 
7851 .keywords: mesh, points
7852 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7853 @*/
7854 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7855 {
7856   PetscInt       d;
7857   PetscErrorCode ierr;
7858 
7859   PetscFunctionBegin;
7860   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7861   PetscValidPointer(depth, 2);
7862   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7863   *depth = d-1;
7864   PetscFunctionReturn(0);
7865 }
7866 
7867 #undef __FUNCT__
7868 #define __FUNCT__ "DMPlexGetDepthStratum"
7869 /*@
7870   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7871 
7872   Not Collective
7873 
7874   Input Parameters:
7875 + dm           - The DMPlex object
7876 - stratumValue - The requested depth
7877 
7878   Output Parameters:
7879 + start - The first point at this depth
7880 - end   - One beyond the last point at this depth
7881 
7882   Level: developer
7883 
7884 .keywords: mesh, points
7885 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7886 @*/
7887 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7888 {
7889   DM_Plex    *mesh = (DM_Plex *) dm->data;
7890   DMLabel        next = mesh->labels;
7891   PetscBool      flg  = PETSC_FALSE;
7892   PetscInt       depth;
7893   PetscErrorCode ierr;
7894 
7895   PetscFunctionBegin;
7896   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7897   if (stratumValue < 0) {
7898     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7899     PetscFunctionReturn(0);
7900   } else {
7901     PetscInt pStart, pEnd;
7902 
7903     if (start) {*start = 0;}
7904     if (end)   {*end   = 0;}
7905     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7906     if (pStart == pEnd) {PetscFunctionReturn(0);}
7907   }
7908   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7909   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7910   /* We should have a generic GetLabel() and a Label class */
7911   while (next) {
7912     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7913     if (flg) break;
7914     next = next->next;
7915   }
7916   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7917   depth = stratumValue;
7918   if ((depth < 0) || (depth >= next->numStrata)) {
7919     if (start) {*start = 0;}
7920     if (end)   {*end   = 0;}
7921   } else {
7922     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7923     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7924   }
7925   PetscFunctionReturn(0);
7926 }
7927 
7928 #undef __FUNCT__
7929 #define __FUNCT__ "DMPlexGetHeightStratum"
7930 /*@
7931   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7932 
7933   Not Collective
7934 
7935   Input Parameters:
7936 + dm           - The DMPlex object
7937 - stratumValue - The requested height
7938 
7939   Output Parameters:
7940 + start - The first point at this height
7941 - end   - One beyond the last point at this height
7942 
7943   Level: developer
7944 
7945 .keywords: mesh, points
7946 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7947 @*/
7948 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7949 {
7950   DM_Plex        *mesh = (DM_Plex *) dm->data;
7951   DMLabel        next = mesh->labels;
7952   PetscBool      flg  = PETSC_FALSE;
7953   PetscInt       depth;
7954   PetscErrorCode ierr;
7955 
7956   PetscFunctionBegin;
7957   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7958   if (stratumValue < 0) {
7959     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7960   } else {
7961     PetscInt pStart, pEnd;
7962 
7963     if (start) {*start = 0;}
7964     if (end)   {*end   = 0;}
7965     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7966     if (pStart == pEnd) {PetscFunctionReturn(0);}
7967   }
7968   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7969   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7970   /* We should have a generic GetLabel() and a Label class */
7971   while (next) {
7972     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7973     if (flg) break;
7974     next = next->next;
7975   }
7976   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7977   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7978   if ((depth < 0) || (depth >= next->numStrata)) {
7979     if (start) {*start = 0;}
7980     if (end)   {*end   = 0;}
7981   } else {
7982     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7983     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7984   }
7985   PetscFunctionReturn(0);
7986 }
7987 
7988 #undef __FUNCT__
7989 #define __FUNCT__ "DMPlexCreateSectionInitial"
7990 /* Set the number of dof on each point and separate by fields */
7991 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7992 {
7993   PetscInt      *numDofTot;
7994   PetscInt       pStart = 0, pEnd = 0;
7995   PetscInt       p, d, f;
7996   PetscErrorCode ierr;
7997 
7998   PetscFunctionBegin;
7999   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
8000   for (d = 0; d <= dim; ++d) {
8001     numDofTot[d] = 0;
8002     for (f = 0; f < numFields; ++f) {
8003       numDofTot[d] += numDof[f*(dim+1)+d];
8004     }
8005   }
8006   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
8007   if (numFields > 0) {
8008     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
8009     if (numComp) {
8010       for (f = 0; f < numFields; ++f) {
8011         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
8012       }
8013     }
8014   }
8015   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8016   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
8017   for (d = 0; d <= dim; ++d) {
8018     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
8019     for (p = pStart; p < pEnd; ++p) {
8020       for (f = 0; f < numFields; ++f) {
8021         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
8022       }
8023       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
8024     }
8025   }
8026   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
8027   PetscFunctionReturn(0);
8028 }
8029 
8030 #undef __FUNCT__
8031 #define __FUNCT__ "DMPlexCreateSectionBCDof"
8032 /* Set the number of dof on each point and separate by fields
8033    If constDof is PETSC_DETERMINE, constrain every dof on the point
8034 */
8035 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
8036 {
8037   PetscInt       numFields;
8038   PetscInt       bc;
8039   PetscErrorCode ierr;
8040 
8041   PetscFunctionBegin;
8042   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8043   for (bc = 0; bc < numBC; ++bc) {
8044     PetscInt        field = 0;
8045     const PetscInt *idx;
8046     PetscInt        n, i;
8047 
8048     if (numFields) {field = bcField[bc];}
8049     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
8050     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8051     for (i = 0; i < n; ++i) {
8052       const PetscInt p = idx[i];
8053       PetscInt       numConst = constDof;
8054 
8055       /* Constrain every dof on the point */
8056       if (numConst < 0) {
8057         if (numFields) {
8058           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
8059         } else {
8060           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
8061         }
8062       }
8063       if (numFields) {
8064         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
8065       }
8066       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
8067     }
8068     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8069   }
8070   PetscFunctionReturn(0);
8071 }
8072 
8073 #undef __FUNCT__
8074 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
8075 /* Set the constrained indices on each point and separate by fields */
8076 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
8077 {
8078   PetscInt      *maxConstraints;
8079   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
8080   PetscErrorCode ierr;
8081 
8082   PetscFunctionBegin;
8083   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8084   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8085   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
8086   for (f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
8087   for (p = pStart; p < pEnd; ++p) {
8088     PetscInt cdof;
8089 
8090     if (numFields) {
8091       for (f = 0; f < numFields; ++f) {
8092         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
8093         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
8094       }
8095     } else {
8096       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8097       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
8098     }
8099   }
8100   for (f = 0; f < numFields; ++f) {
8101     maxConstraints[numFields] += maxConstraints[f];
8102   }
8103   if (maxConstraints[numFields]) {
8104     PetscInt *indices;
8105 
8106     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8107     for (p = pStart; p < pEnd; ++p) {
8108       PetscInt cdof, d;
8109 
8110       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8111       if (cdof) {
8112         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
8113         if (numFields) {
8114           PetscInt numConst = 0, foff = 0;
8115 
8116           for (f = 0; f < numFields; ++f) {
8117             PetscInt cfdof, fdof;
8118 
8119             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8120             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
8121             /* Change constraint numbering from absolute local dof number to field relative local dof number */
8122             for (d = 0; d < cfdof; ++d) {
8123               indices[numConst+d] = d;
8124             }
8125             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
8126             for (d = 0; d < cfdof; ++d) {
8127               indices[numConst+d] += foff;
8128             }
8129             numConst += cfdof;
8130             foff     += fdof;
8131           }
8132           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8133         } else {
8134           for (d = 0; d < cdof; ++d) {
8135             indices[d] = d;
8136           }
8137         }
8138         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8139       }
8140     }
8141     ierr = PetscFree(indices);CHKERRQ(ierr);
8142   }
8143   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
8144   PetscFunctionReturn(0);
8145 }
8146 
8147 #undef __FUNCT__
8148 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
8149 /* Set the constrained field indices on each point */
8150 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
8151 {
8152   const PetscInt *points, *indices;
8153   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
8154   PetscErrorCode  ierr;
8155 
8156   PetscFunctionBegin;
8157   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8158   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8159 
8160   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8161   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8162   if (!constraintIndices) {
8163     PetscInt *idx, i;
8164 
8165     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8166     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8167     for (i = 0; i < maxDof; ++i) {idx[i] = i;}
8168     for (p = 0; p < numPoints; ++p) {
8169       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8170     }
8171     ierr = PetscFree(idx);CHKERRQ(ierr);
8172   } else {
8173     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8174     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8175     for (p = 0; p < numPoints; ++p) {
8176       PetscInt fcdof;
8177 
8178       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8179       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);
8180       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8181     }
8182     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8183   }
8184   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8185   PetscFunctionReturn(0);
8186 }
8187 
8188 #undef __FUNCT__
8189 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8190 /* Set the constrained indices on each point and separate by fields */
8191 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8192 {
8193   PetscInt      *indices;
8194   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8195   PetscErrorCode ierr;
8196 
8197   PetscFunctionBegin;
8198   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8199   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8200   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8201   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8202   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8203   for (p = pStart; p < pEnd; ++p) {
8204     PetscInt cdof, d;
8205 
8206     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8207     if (cdof) {
8208       PetscInt numConst = 0, foff = 0;
8209 
8210       for (f = 0; f < numFields; ++f) {
8211         const PetscInt *fcind;
8212         PetscInt        fdof, fcdof;
8213 
8214         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8215         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8216         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8217         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8218         for (d = 0; d < fcdof; ++d) {
8219           indices[numConst+d] = fcind[d]+foff;
8220         }
8221         foff     += fdof;
8222         numConst += fcdof;
8223       }
8224       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8225       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8226     }
8227   }
8228   ierr = PetscFree(indices);CHKERRQ(ierr);
8229   PetscFunctionReturn(0);
8230 }
8231 
8232 #undef __FUNCT__
8233 #define __FUNCT__ "DMPlexCreateSection"
8234 /*@C
8235   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8236 
8237   Not Collective
8238 
8239   Input Parameters:
8240 + dm        - The DMPlex object
8241 . dim       - The spatial dimension of the problem
8242 . numFields - The number of fields in the problem
8243 . numComp   - An array of size numFields that holds the number of components for each field
8244 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8245 . numBC     - The number of boundary conditions
8246 . bcField   - An array of size numBC giving the field number for each boundry condition
8247 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8248 
8249   Output Parameter:
8250 . section - The PetscSection object
8251 
8252   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
8253   nubmer of dof for field 0 on each edge.
8254 
8255   Level: developer
8256 
8257 .keywords: mesh, elements
8258 .seealso: DMPlexCreate(), PetscSectionCreate()
8259 @*/
8260 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8261 {
8262   PetscErrorCode ierr;
8263 
8264   PetscFunctionBegin;
8265   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8266   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8267   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8268   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8269   {
8270     PetscBool view = PETSC_FALSE;
8271 
8272     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8273     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8274   }
8275   PetscFunctionReturn(0);
8276 }
8277 
8278 #undef __FUNCT__
8279 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8280 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8281 {
8282   PetscSection   section;
8283   PetscErrorCode ierr;
8284 
8285   PetscFunctionBegin;
8286   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8287   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8288   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8289   PetscFunctionReturn(0);
8290 }
8291 
8292 #undef __FUNCT__
8293 #define __FUNCT__ "DMPlexGetCoordinateSection"
8294 /*@
8295   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8296 
8297   Not Collective
8298 
8299   Input Parameter:
8300 . dm - The DMPlex object
8301 
8302   Output Parameter:
8303 . section - The PetscSection object
8304 
8305   Level: intermediate
8306 
8307 .keywords: mesh, coordinates
8308 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8309 @*/
8310 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8311 {
8312   DM             cdm;
8313   PetscErrorCode ierr;
8314 
8315   PetscFunctionBegin;
8316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8317   PetscValidPointer(section, 2);
8318   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8319   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8320   PetscFunctionReturn(0);
8321 }
8322 
8323 #undef __FUNCT__
8324 #define __FUNCT__ "DMPlexSetCoordinateSection"
8325 /*@
8326   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8327 
8328   Not Collective
8329 
8330   Input Parameters:
8331 + dm      - The DMPlex object
8332 - section - The PetscSection object
8333 
8334   Level: intermediate
8335 
8336 .keywords: mesh, coordinates
8337 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8338 @*/
8339 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8340 {
8341   DM             cdm;
8342   PetscErrorCode ierr;
8343 
8344   PetscFunctionBegin;
8345   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8346   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8347   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8348   PetscFunctionReturn(0);
8349 }
8350 
8351 #undef __FUNCT__
8352 #define __FUNCT__ "DMPlexGetConeSection"
8353 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8354 {
8355   DM_Plex *mesh = (DM_Plex *) dm->data;
8356 
8357   PetscFunctionBegin;
8358   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8359   if (section) *section = mesh->coneSection;
8360   PetscFunctionReturn(0);
8361 }
8362 
8363 #undef __FUNCT__
8364 #define __FUNCT__ "DMPlexGetCones"
8365 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8366 {
8367   DM_Plex *mesh = (DM_Plex *) dm->data;
8368 
8369   PetscFunctionBegin;
8370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8371   if (cones) *cones = mesh->cones;
8372   PetscFunctionReturn(0);
8373 }
8374 
8375 #undef __FUNCT__
8376 #define __FUNCT__ "DMPlexGetConeOrientations"
8377 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8378 {
8379   DM_Plex *mesh = (DM_Plex *) dm->data;
8380 
8381   PetscFunctionBegin;
8382   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8383   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8384   PetscFunctionReturn(0);
8385 }
8386 
8387 #undef __FUNCT__
8388 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8389 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8390 {
8391   const PetscInt embedDim = 2;
8392   PetscReal      x = PetscRealPart(point[0]);
8393   PetscReal      y = PetscRealPart(point[1]);
8394   PetscReal      v0[2], J[4], invJ[4], detJ;
8395   PetscReal      xi, eta;
8396   PetscErrorCode ierr;
8397 
8398   PetscFunctionBegin;
8399   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8400   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8401   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8402 
8403   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
8404     *cell = c;
8405   } else {
8406     *cell = -1;
8407   }
8408   PetscFunctionReturn(0);
8409 }
8410 
8411 #undef __FUNCT__
8412 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8413 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8414 {
8415   PetscSection       coordSection;
8416   Vec                coordsLocal;
8417   const PetscScalar *coords;
8418   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8419   PetscReal          x         = PetscRealPart(point[0]);
8420   PetscReal          y         = PetscRealPart(point[1]);
8421   PetscInt           crossings = 0, f;
8422   PetscErrorCode     ierr;
8423 
8424   PetscFunctionBegin;
8425   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8426   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8427   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8428   for (f = 0; f < 4; ++f) {
8429     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8430     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8431     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8432     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8433     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8434     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8435     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8436     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8437     if ((cond1 || cond2)  && above) ++crossings;
8438   }
8439   if (crossings % 2) {
8440     *cell = c;
8441   } else {
8442     *cell = -1;
8443   }
8444   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8445   PetscFunctionReturn(0);
8446 }
8447 
8448 #undef __FUNCT__
8449 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8450 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8451 {
8452   const PetscInt embedDim = 3;
8453   PetscReal      v0[3], J[9], invJ[9], detJ;
8454   PetscReal      x = PetscRealPart(point[0]);
8455   PetscReal      y = PetscRealPart(point[1]);
8456   PetscReal      z = PetscRealPart(point[2]);
8457   PetscReal      xi, eta, zeta;
8458   PetscErrorCode ierr;
8459 
8460   PetscFunctionBegin;
8461   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8462   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8463   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8464   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8465 
8466   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
8467     *cell = c;
8468   } else {
8469     *cell = -1;
8470   }
8471   PetscFunctionReturn(0);
8472 }
8473 
8474 #undef __FUNCT__
8475 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8476 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8477 {
8478   PetscSection       coordSection;
8479   Vec                coordsLocal;
8480   const PetscScalar *coords;
8481   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8482                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8483   PetscBool          found     = PETSC_TRUE;
8484   PetscInt           f;
8485   PetscErrorCode     ierr;
8486 
8487   PetscFunctionBegin;
8488   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8489   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8490   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8491   for (f = 0; f < 6; ++f) {
8492     /* Check the point is under plane */
8493     /*   Get face normal */
8494     PetscReal v_i[3];
8495     PetscReal v_j[3];
8496     PetscReal normal[3];
8497     PetscReal pp[3];
8498     PetscReal dot;
8499 
8500     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8501     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8502     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8503     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8504     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8505     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8506     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8507     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8508     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8509     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8510     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8511     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8512     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8513 
8514     /* Check that projected point is in face (2D location problem) */
8515     if (dot < 0.0) {
8516       found = PETSC_FALSE;
8517       break;
8518     }
8519   }
8520   if (found) {
8521     *cell = c;
8522   } else {
8523     *cell = -1;
8524   }
8525   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8526   PetscFunctionReturn(0);
8527 }
8528 
8529 #undef __FUNCT__
8530 #define __FUNCT__ "DMLocatePoints_Plex"
8531 /*
8532  Need to implement using the guess
8533 */
8534 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8535 {
8536   PetscInt       cell = -1/*, guess = -1*/;
8537   PetscInt       bs, numPoints, p;
8538   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8539   PetscInt      *cells;
8540   PetscScalar   *a;
8541   PetscErrorCode ierr;
8542 
8543   PetscFunctionBegin;
8544   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8545   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8546   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8547   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8548   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8549   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8550   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8551   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);
8552   numPoints /= bs;
8553   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8554   for (p = 0; p < numPoints; ++p) {
8555     const PetscScalar *point = &a[p*bs];
8556 
8557     switch (dim) {
8558     case 2:
8559       for (c = cStart; c < cEnd; ++c) {
8560         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8561         switch (coneSize) {
8562         case 3:
8563           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8564           break;
8565         case 4:
8566           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8567           break;
8568         default:
8569           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8570         }
8571         if (cell >= 0) break;
8572       }
8573       break;
8574     case 3:
8575       for (c = cStart; c < cEnd; ++c) {
8576         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8577         switch (coneSize) {
8578         case 4:
8579           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8580           break;
8581         case 8:
8582           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8583           break;
8584         default:
8585           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8586         }
8587         if (cell >= 0) break;
8588       }
8589       break;
8590     default:
8591       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8592     }
8593     cells[p] = cell;
8594   }
8595   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8596   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8597   PetscFunctionReturn(0);
8598 }
8599 
8600 /******************************** FEM Support **********************************/
8601 
8602 #undef __FUNCT__
8603 #define __FUNCT__ "DMPlexVecGetClosure"
8604 /*@C
8605   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8606 
8607   Not collective
8608 
8609   Input Parameters:
8610 + dm - The DM
8611 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8612 . v - The local vector
8613 - point - The sieve point in the DM
8614 
8615   Output Parameters:
8616 + csize - The number of values in the closure, or PETSC_NULL
8617 - values - The array of values, which is a borrowed array and should not be freed
8618 
8619   Level: intermediate
8620 
8621 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8622 @*/
8623 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8624 {
8625   PetscScalar    *array, *vArray;
8626   PetscInt       *points = PETSC_NULL;
8627   PetscInt        offsets[32];
8628   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8629   PetscErrorCode  ierr;
8630 
8631   PetscFunctionBegin;
8632   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8633   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8634   if (!section) {
8635     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8636   }
8637   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8638   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8639   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8640   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8641   /* Compress out points not in the section */
8642   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8643   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8644     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8645       points[q*2]   = points[p];
8646       points[q*2+1] = points[p+1];
8647       ++q;
8648     }
8649   }
8650   numPoints = q;
8651   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8652     PetscInt dof, fdof;
8653 
8654     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8655     for (f = 0; f < numFields; ++f) {
8656       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8657       offsets[f+1] += fdof;
8658     }
8659     size += dof;
8660   }
8661   for (f = 1; f < numFields; ++f) {
8662     offsets[f+1] += offsets[f];
8663   }
8664   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8665   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8666   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8667   for (p = 0; p < numPoints*2; p += 2) {
8668     PetscInt     o = points[p+1];
8669     PetscInt     dof, off, d;
8670     PetscScalar *varr;
8671 
8672     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8673     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8674     varr = &vArray[off];
8675     if (numFields) {
8676       PetscInt fdof, foff, fcomp, f, c;
8677 
8678       for (f = 0, foff = 0; f < numFields; ++f) {
8679         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8680         if (o >= 0) {
8681           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8682             array[offsets[f]] = varr[foff+d];
8683           }
8684         } else {
8685           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8686           for (d = fdof/fcomp-1; d >= 0; --d) {
8687             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8688               array[offsets[f]] = varr[foff+d*fcomp+c];
8689             }
8690           }
8691         }
8692         foff += fdof;
8693       }
8694     } else {
8695       if (o >= 0) {
8696         for (d = 0; d < dof; ++d, ++offsets[0]) {
8697           array[offsets[0]] = varr[d];
8698         }
8699       } else {
8700         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8701           array[offsets[0]] = varr[d];
8702         }
8703       }
8704     }
8705   }
8706   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8707   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8708   if (csize) *csize = size;
8709   *values = array;
8710   PetscFunctionReturn(0);
8711 }
8712 
8713 #undef __FUNCT__
8714 #define __FUNCT__ "DMPlexVecRestoreClosure"
8715 /*@C
8716   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8717 
8718   Not collective
8719 
8720   Input Parameters:
8721 + dm - The DM
8722 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8723 . v - The local vector
8724 . point - The sieve point in the DM
8725 . csize - The number of values in the closure, or PETSC_NULL
8726 - values - The array of values, which is a borrowed array and should not be freed
8727 
8728   Level: intermediate
8729 
8730 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8731 @*/
8732 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8733 {
8734   PetscInt        size = 0;
8735   PetscErrorCode  ierr;
8736 
8737   PetscFunctionBegin;
8738   /* Should work without recalculating size */
8739   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8740   PetscFunctionReturn(0);
8741 }
8742 
8743 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8744 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8745 
8746 #undef __FUNCT__
8747 #define __FUNCT__ "updatePoint_private"
8748 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8749 {
8750   PetscInt        cdof;  /* The number of constraints on this point */
8751   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8752   PetscScalar    *a;
8753   PetscInt        off, cind = 0, k;
8754   PetscErrorCode  ierr;
8755 
8756   PetscFunctionBegin;
8757   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8758   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8759   a    = &array[off];
8760   if (!cdof || setBC) {
8761     if (orientation >= 0) {
8762       for (k = 0; k < dof; ++k) {
8763         fuse(&a[k], values[k]);
8764       }
8765     } else {
8766       for (k = 0; k < dof; ++k) {
8767         fuse(&a[k], values[dof-k-1]);
8768       }
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])) {++cind; continue;}
8775         fuse(&a[k], values[k]);
8776       }
8777     } else {
8778       for (k = 0; k < dof; ++k) {
8779         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8780         fuse(&a[k], values[dof-k-1]);
8781       }
8782     }
8783   }
8784   PetscFunctionReturn(0);
8785 }
8786 
8787 #undef __FUNCT__
8788 #define __FUNCT__ "updatePointFields_private"
8789 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8790 {
8791   PetscScalar   *a;
8792   PetscInt       numFields, off, foff, f;
8793   PetscErrorCode ierr;
8794 
8795   PetscFunctionBegin;
8796   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8797   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8798   a    = &array[off];
8799   for (f = 0, foff = 0; f < numFields; ++f) {
8800     PetscInt        fdof, fcomp, fcdof;
8801     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8802     PetscInt        cind = 0, k, c;
8803 
8804     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8805     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8806     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8807     if (!fcdof || setBC) {
8808       if (orientation >= 0) {
8809         for (k = 0; k < fdof; ++k) {
8810           fuse(&a[foff+k], values[foffs[f]+k]);
8811         }
8812       } else {
8813         for (k = fdof/fcomp-1; k >= 0; --k) {
8814           for (c = 0; c < fcomp; ++c) {
8815             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8816           }
8817         }
8818       }
8819     } else {
8820       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8821       if (orientation >= 0) {
8822         for (k = 0; k < fdof; ++k) {
8823           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8824           fuse(&a[foff+k], values[foffs[f]+k]);
8825         }
8826       } else {
8827         for (k = fdof/fcomp-1; k >= 0; --k) {
8828           for (c = 0; c < fcomp; ++c) {
8829             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8830             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8831           }
8832         }
8833       }
8834     }
8835     foff     += fdof;
8836     foffs[f] += fdof;
8837   }
8838   PetscFunctionReturn(0);
8839 }
8840 
8841 #undef __FUNCT__
8842 #define __FUNCT__ "DMPlexVecSetClosure"
8843 /*@C
8844   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8845 
8846   Not collective
8847 
8848   Input Parameters:
8849 + dm - The DM
8850 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8851 . v - The local vector
8852 . point - The sieve point in the DM
8853 . values - The array of values, which is a borrowed array and should not be freed
8854 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8855 
8856   Level: intermediate
8857 
8858 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8859 @*/
8860 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8861 {
8862   PetscScalar    *array;
8863   PetscInt       *points = PETSC_NULL;
8864   PetscInt        offsets[32];
8865   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8866   PetscErrorCode  ierr;
8867 
8868   PetscFunctionBegin;
8869   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8870   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8871   if (!section) {
8872     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8873   }
8874   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8875   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8876   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8877   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8878   /* Compress out points not in the section */
8879   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8880   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8881     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8882       points[q*2]   = points[p];
8883       points[q*2+1] = points[p+1];
8884       ++q;
8885     }
8886   }
8887   numPoints = q;
8888   for (p = 0; p < numPoints*2; p += 2) {
8889     PetscInt fdof;
8890 
8891     for (f = 0; f < numFields; ++f) {
8892       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8893       offsets[f+1] += fdof;
8894     }
8895   }
8896   for (f = 1; f < numFields; ++f) {
8897     offsets[f+1] += offsets[f];
8898   }
8899   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8900   if (numFields) {
8901     switch (mode) {
8902     case INSERT_VALUES:
8903       for (p = 0; p < numPoints*2; p += 2) {
8904         PetscInt o = points[p+1];
8905         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8906       } break;
8907     case INSERT_ALL_VALUES:
8908       for (p = 0; p < numPoints*2; p += 2) {
8909         PetscInt o = points[p+1];
8910         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8911       } break;
8912     case ADD_VALUES:
8913       for (p = 0; p < numPoints*2; p += 2) {
8914         PetscInt o = points[p+1];
8915         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8916       } break;
8917     case ADD_ALL_VALUES:
8918       for (p = 0; p < numPoints*2; p += 2) {
8919         PetscInt o = points[p+1];
8920         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8921       } break;
8922     default:
8923       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8924     }
8925   } else {
8926     switch (mode) {
8927     case INSERT_VALUES:
8928       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8929         PetscInt o = points[p+1];
8930         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8931         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8932       } break;
8933     case INSERT_ALL_VALUES:
8934       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8935         PetscInt o = points[p+1];
8936         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8937         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8938       } break;
8939     case ADD_VALUES:
8940       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8941         PetscInt o = points[p+1];
8942         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8943         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8944       } break;
8945     case ADD_ALL_VALUES:
8946       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8947         PetscInt o = points[p+1];
8948         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8949         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8950       } break;
8951     default:
8952       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8953     }
8954   }
8955   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8956   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8957   PetscFunctionReturn(0);
8958 }
8959 
8960 #undef __FUNCT__
8961 #define __FUNCT__ "DMPlexPrintMatSetValues"
8962 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8963 {
8964   PetscMPIInt    rank;
8965   PetscInt       i, j;
8966   PetscErrorCode ierr;
8967 
8968   PetscFunctionBegin;
8969   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8970   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8971   for (i = 0; i < numIndices; i++) {
8972     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8973   }
8974   for (i = 0; i < numIndices; i++) {
8975     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8976     for (j = 0; j < numIndices; j++) {
8977 #if defined(PETSC_USE_COMPLEX)
8978       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8979 #else
8980       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8981 #endif
8982     }
8983     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8984   }
8985   PetscFunctionReturn(0);
8986 }
8987 
8988 #undef __FUNCT__
8989 #define __FUNCT__ "indicesPoint_private"
8990 /* . off - The global offset of this point */
8991 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8992 {
8993   PetscInt        cdof;  /* The number of constraints on this point */
8994   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8995   PetscInt        cind = 0, k;
8996   PetscErrorCode  ierr;
8997 
8998   PetscFunctionBegin;
8999   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
9000   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
9001   if (!cdof || setBC) {
9002     if (orientation >= 0) {
9003       for (k = 0; k < dof; ++k) {
9004         indices[k] = off+k;
9005       }
9006     } else {
9007       for (k = 0; k < dof; ++k) {
9008         indices[dof-k-1] = off+k;
9009       }
9010     }
9011   } else {
9012     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
9013     if (orientation >= 0) {
9014       for (k = 0; k < dof; ++k) {
9015         if ((cind < cdof) && (k == cdofs[cind])) {
9016           /* Insert check for returning constrained indices */
9017           indices[k] = -(off+k+1);
9018           ++cind;
9019         } else {
9020           indices[k] = off+k-cind;
9021         }
9022       }
9023     } else {
9024       for (k = 0; k < dof; ++k) {
9025         if ((cind < cdof) && (k == cdofs[cind])) {
9026           /* Insert check for returning constrained indices */
9027           indices[dof-k-1] = -(off+k+1);
9028           ++cind;
9029         } else {
9030           indices[dof-k-1] = off+k-cind;
9031         }
9032       }
9033     }
9034   }
9035   PetscFunctionReturn(0);
9036 }
9037 
9038 #undef __FUNCT__
9039 #define __FUNCT__ "indicesPointFields_private"
9040 /* . off - The global offset of this point */
9041 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
9042 {
9043   PetscInt       numFields, foff, f;
9044   PetscErrorCode ierr;
9045 
9046   PetscFunctionBegin;
9047   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9048   for (f = 0, foff = 0; f < numFields; ++f) {
9049     PetscInt        fdof, fcomp, cfdof;
9050     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
9051     PetscInt        cind = 0, k, c;
9052 
9053     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
9054     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
9055     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
9056     if (!cfdof || setBC) {
9057       if (orientation >= 0) {
9058         for (k = 0; k < fdof; ++k) {
9059           indices[foffs[f]+k] = off+foff+k;
9060         }
9061       } else {
9062         for (k = fdof/fcomp-1; k >= 0; --k) {
9063           for (c = 0; c < fcomp; ++c) {
9064             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
9065           }
9066         }
9067       }
9068     } else {
9069       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
9070       if (orientation >= 0) {
9071         for (k = 0; k < fdof; ++k) {
9072           if ((cind < cfdof) && (k == fcdofs[cind])) {
9073             indices[foffs[f]+k] = -(off+foff+k+1);
9074             ++cind;
9075           } else {
9076             indices[foffs[f]+k] = off+foff+k-cind;
9077           }
9078         }
9079       } else {
9080         for (k = fdof/fcomp-1; k >= 0; --k) {
9081           for (c = 0; c < fcomp; ++c) {
9082             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
9083               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
9084               ++cind;
9085             } else {
9086               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
9087             }
9088           }
9089         }
9090       }
9091     }
9092     foff     += fdof - cfdof;
9093     foffs[f] += fdof;
9094   }
9095   PetscFunctionReturn(0);
9096 }
9097 
9098 #undef __FUNCT__
9099 #define __FUNCT__ "DMPlexMatSetClosure"
9100 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
9101 {
9102   DM_Plex     *mesh   = (DM_Plex *) dm->data;
9103   PetscInt       *points = PETSC_NULL;
9104   PetscInt       *indices;
9105   PetscInt        offsets[32];
9106   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
9107   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
9108   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
9109   PetscErrorCode  ierr;
9110 
9111   PetscFunctionBegin;
9112   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9113   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
9114   if (useDefault) {
9115     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9116   }
9117   if (useGlobalDefault) {
9118     if (useDefault) {
9119       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
9120     } else {
9121       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9122     }
9123   }
9124   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9125   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
9126   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
9127   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9128   /* Compress out points not in the section */
9129   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
9130   for (p = 0, q = 0; p < numPoints*2; p += 2) {
9131     if ((points[p] >= pStart) && (points[p] < pEnd)) {
9132       points[q*2]   = points[p];
9133       points[q*2+1] = points[p+1];
9134       ++q;
9135     }
9136   }
9137   numPoints = q;
9138   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
9139     PetscInt fdof;
9140 
9141     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
9142     for (f = 0; f < numFields; ++f) {
9143       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
9144       offsets[f+1] += fdof;
9145     }
9146     numIndices += dof;
9147   }
9148   for (f = 1; f < numFields; ++f) {
9149     offsets[f+1] += offsets[f];
9150   }
9151   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
9152   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9153   if (numFields) {
9154     for (p = 0; p < numPoints*2; p += 2) {
9155       PetscInt o = points[p+1];
9156       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9157       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
9158     }
9159   } else {
9160     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
9161       PetscInt o = points[p+1];
9162       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9163       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
9164     }
9165   }
9166   if (useGlobalDefault && !useDefault) {
9167     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9168   }
9169   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
9170   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9171   if (ierr) {
9172     PetscMPIInt    rank;
9173     PetscErrorCode ierr2;
9174 
9175     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
9176     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9177     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9178     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9179     CHKERRQ(ierr);
9180   }
9181   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9182   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9183   PetscFunctionReturn(0);
9184 }
9185 
9186 #undef __FUNCT__
9187 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9188 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9189 {
9190   PetscSection       coordSection;
9191   Vec                coordinates;
9192   const PetscScalar *coords;
9193   const PetscInt     dim = 2;
9194   PetscInt           d, f;
9195   PetscErrorCode     ierr;
9196 
9197   PetscFunctionBegin;
9198   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9199   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9200   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9201   if (v0) {
9202     for (d = 0; d < dim; d++) {
9203       v0[d] = PetscRealPart(coords[d]);
9204     }
9205   }
9206   if (J) {
9207     for (d = 0; d < dim; d++) {
9208       for (f = 0; f < dim; f++) {
9209         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9210       }
9211     }
9212     *detJ = J[0]*J[3] - J[1]*J[2];
9213 #if 0
9214     if (detJ < 0.0) {
9215       const PetscReal xLength = mesh->periodicity[0];
9216 
9217       if (xLength != 0.0) {
9218         PetscReal v0x = coords[0*dim+0];
9219 
9220         if (v0x == 0.0) {
9221           v0x = v0[0] = xLength;
9222         }
9223         for (f = 0; f < dim; f++) {
9224           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9225 
9226           J[0*dim+f] = 0.5*(px - v0x);
9227         }
9228       }
9229       detJ = J[0]*J[3] - J[1]*J[2];
9230     }
9231 #endif
9232     PetscLogFlops(8.0 + 3.0);
9233   }
9234   if (invJ) {
9235     const PetscReal invDet = 1.0/(*detJ);
9236 
9237     invJ[0] =  invDet*J[3];
9238     invJ[1] = -invDet*J[1];
9239     invJ[2] = -invDet*J[2];
9240     invJ[3] =  invDet*J[0];
9241     PetscLogFlops(5.0);
9242   }
9243   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9244   PetscFunctionReturn(0);
9245 }
9246 
9247 #undef __FUNCT__
9248 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9249 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9250 {
9251   PetscSection       coordSection;
9252   Vec                coordinates;
9253   const PetscScalar *coords;
9254   const PetscInt     dim = 2;
9255   PetscInt           d, f;
9256   PetscErrorCode     ierr;
9257 
9258   PetscFunctionBegin;
9259   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9260   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9261   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9262   if (v0) {
9263     for (d = 0; d < dim; d++) {
9264       v0[d] = PetscRealPart(coords[d]);
9265     }
9266   }
9267   if (J) {
9268     for (d = 0; d < dim; d++) {
9269       for (f = 0; f < dim; f++) {
9270         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9271       }
9272     }
9273     *detJ = J[0]*J[3] - J[1]*J[2];
9274     PetscLogFlops(8.0 + 3.0);
9275   }
9276   if (invJ) {
9277     const PetscReal invDet = 1.0/(*detJ);
9278 
9279     invJ[0] =  invDet*J[3];
9280     invJ[1] = -invDet*J[1];
9281     invJ[2] = -invDet*J[2];
9282     invJ[3] =  invDet*J[0];
9283     PetscLogFlops(5.0);
9284   }
9285   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9286   PetscFunctionReturn(0);
9287 }
9288 
9289 #undef __FUNCT__
9290 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9291 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9292 {
9293   PetscSection       coordSection;
9294   Vec                coordinates;
9295   const PetscScalar *coords;
9296   const PetscInt     dim = 3;
9297   PetscInt           d, f;
9298   PetscErrorCode     ierr;
9299 
9300   PetscFunctionBegin;
9301   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9302   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9303   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9304   if (v0) {
9305     for (d = 0; d < dim; d++) {
9306       v0[d] = PetscRealPart(coords[d]);
9307     }
9308   }
9309   if (J) {
9310     for (d = 0; d < dim; d++) {
9311       for (f = 0; f < dim; f++) {
9312         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9313       }
9314     }
9315     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9316     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9317              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9318              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9319     PetscLogFlops(18.0 + 12.0);
9320   }
9321   if (invJ) {
9322     const PetscReal invDet = 1.0/(*detJ);
9323 
9324     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9325     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9326     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9327     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9328     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9329     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9330     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9331     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9332     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9333     PetscLogFlops(37.0);
9334   }
9335   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9336   PetscFunctionReturn(0);
9337 }
9338 
9339 #undef __FUNCT__
9340 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9341 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9342 {
9343   PetscSection       coordSection;
9344   Vec                coordinates;
9345   const PetscScalar *coords;
9346   const PetscInt     dim = 3;
9347   PetscInt           d;
9348   PetscErrorCode     ierr;
9349 
9350   PetscFunctionBegin;
9351   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9352   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9353   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9354   if (v0) {
9355     for (d = 0; d < dim; d++) {
9356       v0[d] = PetscRealPart(coords[d]);
9357     }
9358   }
9359   if (J) {
9360     for (d = 0; d < dim; d++) {
9361       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9362       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9363       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9364     }
9365     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9366              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9367              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9368     PetscLogFlops(18.0 + 12.0);
9369   }
9370   if (invJ) {
9371     const PetscReal invDet = -1.0/(*detJ);
9372 
9373     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9374     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9375     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9376     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9377     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9378     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9379     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9380     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9381     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9382     PetscLogFlops(37.0);
9383   }
9384   *detJ *= 8.0;
9385   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9386   PetscFunctionReturn(0);
9387 }
9388 
9389 #undef __FUNCT__
9390 #define __FUNCT__ "DMPlexComputeCellGeometry"
9391 /*@C
9392   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9393 
9394   Collective on DM
9395 
9396   Input Arguments:
9397 + dm   - the DM
9398 - cell - the cell
9399 
9400   Output Arguments:
9401 + v0   - the translation part of this affine transform
9402 . J    - the Jacobian of the transform to the reference element
9403 . invJ - the inverse of the Jacobian
9404 - detJ - the Jacobian determinant
9405 
9406   Level: advanced
9407 
9408 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9409 @*/
9410 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9411 {
9412   PetscInt       dim, coneSize;
9413   PetscErrorCode ierr;
9414 
9415   PetscFunctionBegin;
9416   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9417   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9418   switch (dim) {
9419   case 2:
9420     switch (coneSize) {
9421     case 3:
9422       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9423       break;
9424     case 4:
9425       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9426       break;
9427     default:
9428       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9429     }
9430     break;
9431   case 3:
9432     switch (coneSize) {
9433     case 4:
9434       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9435       break;
9436     case 8:
9437       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9438       break;
9439     default:
9440       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9441     }
9442     break;
9443   default:
9444     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9445   }
9446   PetscFunctionReturn(0);
9447 }
9448 
9449 #undef __FUNCT__
9450 #define __FUNCT__ "DMPlexGetFaceOrientation"
9451 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9452 {
9453   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9454   PetscBool      posOrient = PETSC_FALSE;
9455   const PetscInt debug     = 0;
9456   PetscInt       cellDim, faceSize, f;
9457   PetscErrorCode ierr;
9458 
9459   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9460   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9461 
9462   if (cellDim == numCorners-1) {
9463     /* Simplices */
9464     faceSize  = numCorners-1;
9465     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9466   } else if (cellDim == 1 && numCorners == 3) {
9467     /* Quadratic line */
9468     faceSize  = 1;
9469     posOrient = PETSC_TRUE;
9470   } else if (cellDim == 2 && numCorners == 4) {
9471     /* Quads */
9472     faceSize  = 2;
9473     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9474       posOrient = PETSC_TRUE;
9475     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9476       posOrient = PETSC_TRUE;
9477     } else {
9478       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9479         posOrient = PETSC_FALSE;
9480       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9481     }
9482   } else if (cellDim == 2 && numCorners == 6) {
9483     /* Quadratic triangle (I hate this) */
9484     /* Edges are determined by the first 2 vertices (corners of edges) */
9485     const PetscInt faceSizeTri = 3;
9486     PetscInt  sortedIndices[3], i, iFace;
9487     PetscBool found = PETSC_FALSE;
9488     PetscInt  faceVerticesTriSorted[9] = {
9489       0, 3,  4, /* bottom */
9490       1, 4,  5, /* right */
9491       2, 3,  5, /* left */
9492     };
9493     PetscInt  faceVerticesTri[9] = {
9494       0, 3,  4, /* bottom */
9495       1, 4,  5, /* right */
9496       2, 5,  3, /* left */
9497     };
9498 
9499     faceSize = faceSizeTri;
9500     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9501     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9502     for (iFace = 0; iFace < 3; ++iFace) {
9503       const PetscInt ii = iFace*faceSizeTri;
9504       PetscInt       fVertex, cVertex;
9505 
9506       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9507           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9508         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9509           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9510             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9511               faceVertices[fVertex] = origVertices[cVertex];
9512               break;
9513             }
9514           }
9515         }
9516         found = PETSC_TRUE;
9517         break;
9518       }
9519     }
9520     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9521     if (posOriented) {*posOriented = PETSC_TRUE;}
9522     PetscFunctionReturn(0);
9523   } else if (cellDim == 2 && numCorners == 9) {
9524     /* Quadratic quad (I hate this) */
9525     /* Edges are determined by the first 2 vertices (corners of edges) */
9526     const PetscInt faceSizeQuad = 3;
9527     PetscInt  sortedIndices[3], i, iFace;
9528     PetscBool found = PETSC_FALSE;
9529     PetscInt  faceVerticesQuadSorted[12] = {
9530       0, 1,  4, /* bottom */
9531       1, 2,  5, /* right */
9532       2, 3,  6, /* top */
9533       0, 3,  7, /* left */
9534     };
9535     PetscInt  faceVerticesQuad[12] = {
9536       0, 1,  4, /* bottom */
9537       1, 2,  5, /* right */
9538       2, 3,  6, /* top */
9539       3, 0,  7, /* left */
9540     };
9541 
9542     faceSize = faceSizeQuad;
9543     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9544     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9545     for (iFace = 0; iFace < 4; ++iFace) {
9546       const PetscInt ii = iFace*faceSizeQuad;
9547       PetscInt       fVertex, cVertex;
9548 
9549       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9550           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9551         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9552           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9553             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9554               faceVertices[fVertex] = origVertices[cVertex];
9555               break;
9556             }
9557           }
9558         }
9559         found = PETSC_TRUE;
9560         break;
9561       }
9562     }
9563     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9564     if (posOriented) {*posOriented = PETSC_TRUE;}
9565     PetscFunctionReturn(0);
9566   } else if (cellDim == 3 && numCorners == 8) {
9567     /* Hexes
9568        A hex is two oriented quads with the normal of the first
9569        pointing up at the second.
9570 
9571           7---6
9572          /|  /|
9573         4---5 |
9574         | 3-|-2
9575         |/  |/
9576         0---1
9577 
9578         Faces are determined by the first 4 vertices (corners of faces) */
9579     const PetscInt faceSizeHex = 4;
9580     PetscInt  sortedIndices[4], i, iFace;
9581     PetscBool found = PETSC_FALSE;
9582     PetscInt faceVerticesHexSorted[24] = {
9583       0, 1, 2, 3,  /* bottom */
9584       4, 5, 6, 7,  /* top */
9585       0, 1, 4, 5,  /* front */
9586       1, 2, 5, 6,  /* right */
9587       2, 3, 6, 7,  /* back */
9588       0, 3, 4, 7,  /* left */
9589     };
9590     PetscInt faceVerticesHex[24] = {
9591       3, 2, 1, 0,  /* bottom */
9592       4, 5, 6, 7,  /* top */
9593       0, 1, 5, 4,  /* front */
9594       1, 2, 6, 5,  /* right */
9595       2, 3, 7, 6,  /* back */
9596       3, 0, 4, 7,  /* left */
9597     };
9598 
9599     faceSize = faceSizeHex;
9600     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9601     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9602     for (iFace = 0; iFace < 6; ++iFace) {
9603       const PetscInt ii = iFace*faceSizeHex;
9604       PetscInt       fVertex, cVertex;
9605 
9606       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9607           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9608           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9609           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9610         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9611           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9612             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9613               faceVertices[fVertex] = origVertices[cVertex];
9614               break;
9615             }
9616           }
9617         }
9618         found = PETSC_TRUE;
9619         break;
9620       }
9621     }
9622     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9623     if (posOriented) {*posOriented = PETSC_TRUE;}
9624     PetscFunctionReturn(0);
9625   } else if (cellDim == 3 && numCorners == 10) {
9626     /* Quadratic tet */
9627     /* Faces are determined by the first 3 vertices (corners of faces) */
9628     const PetscInt faceSizeTet = 6;
9629     PetscInt  sortedIndices[6], i, iFace;
9630     PetscBool found = PETSC_FALSE;
9631     PetscInt faceVerticesTetSorted[24] = {
9632       0, 1, 2,  6, 7, 8, /* bottom */
9633       0, 3, 4,  6, 7, 9,  /* front */
9634       1, 4, 5,  7, 8, 9,  /* right */
9635       2, 3, 5,  6, 8, 9,  /* left */
9636     };
9637     PetscInt faceVerticesTet[24] = {
9638       0, 1, 2,  6, 7, 8, /* bottom */
9639       0, 4, 3,  6, 7, 9,  /* front */
9640       1, 5, 4,  7, 8, 9,  /* right */
9641       2, 3, 5,  8, 6, 9,  /* left */
9642     };
9643 
9644     faceSize = faceSizeTet;
9645     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9646     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9647     for (iFace=0; iFace < 4; ++iFace) {
9648       const PetscInt ii = iFace*faceSizeTet;
9649       PetscInt       fVertex, cVertex;
9650 
9651       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9652           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9653           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9654           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9655         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9656           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9657             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9658               faceVertices[fVertex] = origVertices[cVertex];
9659               break;
9660             }
9661           }
9662         }
9663         found = PETSC_TRUE;
9664         break;
9665       }
9666     }
9667     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9668     if (posOriented) {*posOriented = PETSC_TRUE;}
9669     PetscFunctionReturn(0);
9670   } else if (cellDim == 3 && numCorners == 27) {
9671     /* Quadratic hexes (I hate this)
9672        A hex is two oriented quads with the normal of the first
9673        pointing up at the second.
9674 
9675          7---6
9676         /|  /|
9677        4---5 |
9678        | 3-|-2
9679        |/  |/
9680        0---1
9681 
9682        Faces are determined by the first 4 vertices (corners of faces) */
9683     const PetscInt faceSizeQuadHex = 9;
9684     PetscInt  sortedIndices[9], i, iFace;
9685     PetscBool found = PETSC_FALSE;
9686     PetscInt faceVerticesQuadHexSorted[54] = {
9687       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9688       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9689       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9690       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9691       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9692       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9693     };
9694     PetscInt faceVerticesQuadHex[54] = {
9695       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9696       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9697       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9698       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9699       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9700       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9701     };
9702 
9703     faceSize = faceSizeQuadHex;
9704     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9705     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9706     for (iFace = 0; iFace < 6; ++iFace) {
9707       const PetscInt ii = iFace*faceSizeQuadHex;
9708       PetscInt       fVertex, cVertex;
9709 
9710       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9711           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9712           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9713           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9714         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9715           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9716             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9717               faceVertices[fVertex] = origVertices[cVertex];
9718               break;
9719             }
9720           }
9721         }
9722         found = PETSC_TRUE;
9723         break;
9724       }
9725     }
9726     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9727     if (posOriented) {*posOriented = PETSC_TRUE;}
9728     PetscFunctionReturn(0);
9729   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9730   if (!posOrient) {
9731     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9732     for (f = 0; f < faceSize; ++f) {
9733       faceVertices[f] = origVertices[faceSize-1 - f];
9734     }
9735   } else {
9736     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9737     for (f = 0; f < faceSize; ++f) {
9738       faceVertices[f] = origVertices[f];
9739     }
9740   }
9741   if (posOriented) {*posOriented = posOrient;}
9742   PetscFunctionReturn(0);
9743 }
9744 
9745 #undef __FUNCT__
9746 #define __FUNCT__ "DMPlexGetOrientedFace"
9747 /*
9748     Given a cell and a face, as a set of vertices,
9749       return the oriented face, as a set of vertices, in faceVertices
9750     The orientation is such that the face normal points out of the cell
9751 */
9752 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9753 {
9754   const PetscInt *cone = PETSC_NULL;
9755   PetscInt        coneSize, v, f, v2;
9756   PetscInt        oppositeVertex = -1;
9757   PetscErrorCode  ierr;
9758 
9759   PetscFunctionBegin;
9760   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9761   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9762   for (v = 0, v2 = 0; v < coneSize; ++v) {
9763     PetscBool found  = PETSC_FALSE;
9764 
9765     for (f = 0; f < faceSize; ++f) {
9766       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9767     }
9768     if (found) {
9769       indices[v2]      = v;
9770       origVertices[v2] = cone[v];
9771       ++v2;
9772     } else {
9773       oppositeVertex = v;
9774     }
9775   }
9776   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9777   PetscFunctionReturn(0);
9778 }
9779 
9780 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9781 {
9782   switch (i) {
9783   case 0:
9784     switch (j) {
9785     case 0: return 0;
9786     case 1:
9787       switch (k) {
9788       case 0: return 0;
9789       case 1: return 0;
9790       case 2: return 1;
9791       }
9792     case 2:
9793       switch (k) {
9794       case 0: return 0;
9795       case 1: return -1;
9796       case 2: return 0;
9797       }
9798     }
9799   case 1:
9800     switch (j) {
9801     case 0:
9802       switch (k) {
9803       case 0: return 0;
9804       case 1: return 0;
9805       case 2: return -1;
9806       }
9807     case 1: return 0;
9808     case 2:
9809       switch (k) {
9810       case 0: return 1;
9811       case 1: return 0;
9812       case 2: return 0;
9813       }
9814     }
9815   case 2:
9816     switch (j) {
9817     case 0:
9818       switch (k) {
9819       case 0: return 0;
9820       case 1: return 1;
9821       case 2: return 0;
9822       }
9823     case 1:
9824       switch (k) {
9825       case 0: return -1;
9826       case 1: return 0;
9827       case 2: return 0;
9828       }
9829     case 2: return 0;
9830     }
9831   }
9832   return 0;
9833 }
9834 
9835 #undef __FUNCT__
9836 #define __FUNCT__ "DMPlexCreateRigidBody"
9837 /*@C
9838   DMPlexCreateRigidBody - create rigid body modes from coordinates
9839 
9840   Collective on DM
9841 
9842   Input Arguments:
9843 + dm - the DM
9844 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9845 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9846 
9847   Output Argument:
9848 . sp - the null space
9849 
9850   Note: This is necessary to take account of Dirichlet conditions on the displacements
9851 
9852   Level: advanced
9853 
9854 .seealso: MatNullSpaceCreate()
9855 @*/
9856 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9857 {
9858   MPI_Comm       comm = ((PetscObject) dm)->comm;
9859   Vec            coordinates, localMode, mode[6];
9860   PetscSection   coordSection;
9861   PetscScalar   *coords;
9862   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9863   PetscErrorCode ierr;
9864 
9865   PetscFunctionBegin;
9866   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9867   if (dim == 1) {
9868     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9869     PetscFunctionReturn(0);
9870   }
9871   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9872   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9873   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9874   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9875   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9876   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9877   m    = (dim*(dim+1))/2;
9878   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9879   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9880   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9881   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9882   /* Assume P1 */
9883   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9884   for (d = 0; d < dim; ++d) {
9885     PetscScalar values[3] = {0.0, 0.0, 0.0};
9886 
9887     values[d] = 1.0;
9888     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9889     for (v = vStart; v < vEnd; ++v) {
9890       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9891     }
9892     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9893     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9894   }
9895   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9896   for (d = dim; d < dim*(dim+1)/2; ++d) {
9897     PetscInt i, j, k = dim > 2 ? d - dim : d;
9898 
9899     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9900     for (v = vStart; v < vEnd; ++v) {
9901       PetscScalar values[3] = {0.0, 0.0, 0.0};
9902       PetscInt    off;
9903 
9904       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9905       for (i = 0; i < dim; ++i) {
9906         for (j = 0; j < dim; ++j) {
9907           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9908         }
9909       }
9910       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9911     }
9912     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9913     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9914   }
9915   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9916   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9917   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9918   /* Orthonormalize system */
9919   for (i = dim; i < m; ++i) {
9920     PetscScalar dots[6];
9921 
9922     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9923     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9924     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9925     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9926   }
9927   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9928   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9929   PetscFunctionReturn(0);
9930 }
9931 
9932 #undef __FUNCT__
9933 #define __FUNCT__ "DMPlexGetHybridBounds"
9934 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9935 {
9936   DM_Plex       *mesh = (DM_Plex *) dm->data;
9937   PetscInt       dim;
9938   PetscErrorCode ierr;
9939 
9940   PetscFunctionBegin;
9941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9942   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9943   if (cMax) *cMax = mesh->hybridPointMax[dim];
9944   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9945   if (eMax) *eMax = mesh->hybridPointMax[1];
9946   if (vMax) *vMax = mesh->hybridPointMax[0];
9947   PetscFunctionReturn(0);
9948 }
9949 
9950 #undef __FUNCT__
9951 #define __FUNCT__ "DMPlexSetHybridBounds"
9952 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9953 {
9954   DM_Plex       *mesh = (DM_Plex *) dm->data;
9955   PetscInt       dim;
9956   PetscErrorCode ierr;
9957 
9958   PetscFunctionBegin;
9959   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9960   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9961   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9962   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9963   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9964   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9965   PetscFunctionReturn(0);
9966 }
9967 
9968 #undef __FUNCT__
9969 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9970 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9971 {
9972   DM_Plex *mesh = (DM_Plex *) dm->data;
9973 
9974   PetscFunctionBegin;
9975   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9976   PetscValidPointer(cellHeight, 2);
9977   *cellHeight = mesh->vtkCellHeight;
9978   PetscFunctionReturn(0);
9979 }
9980 
9981 #undef __FUNCT__
9982 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9983 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9984 {
9985   DM_Plex *mesh = (DM_Plex *) dm->data;
9986 
9987   PetscFunctionBegin;
9988   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9989   mesh->vtkCellHeight = cellHeight;
9990   PetscFunctionReturn(0);
9991 }
9992 
9993 #undef __FUNCT__
9994 #define __FUNCT__ "DMPlexInsertFace_Private"
9995 /*
9996   DMPlexInsertFace_Private - Puts a face into the mesh
9997 
9998   Not collective
9999 
10000   Input Parameters:
10001   + dm              - The DMPlex
10002   . numFaceVertex   - The number of vertices in the face
10003   . faceVertices    - The vertices in the face for dm
10004   . subfaceVertices - The vertices in the face for subdm
10005   . numCorners      - The number of vertices in the cell
10006   . cell            - A cell in dm containing the face
10007   . subcell         - A cell in subdm containing the face
10008   . firstFace       - First face in the mesh
10009   - newFacePoint    - Next face in the mesh
10010 
10011   Output Parameters:
10012   . newFacePoint - Contains next face point number on input, updated on output
10013 
10014   Level: developer
10015 */
10016 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)
10017 {
10018   MPI_Comm        comm    = ((PetscObject) dm)->comm;
10019   DM_Plex     *submesh = (DM_Plex *) subdm->data;
10020   const PetscInt *faces;
10021   PetscInt        numFaces, coneSize;
10022   PetscErrorCode  ierr;
10023 
10024   PetscFunctionBegin;
10025   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
10026   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
10027 #if 0
10028   /* Cannot use this because support() has not been constructed yet */
10029   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10030 #else
10031   {
10032     PetscInt f;
10033 
10034     numFaces = 0;
10035     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
10036     for (f = firstFace; f < *newFacePoint; ++f) {
10037       PetscInt dof, off, d;
10038 
10039       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
10040       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
10041       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
10042       for (d = 0; d < dof; ++d) {
10043         const PetscInt p = submesh->cones[off+d];
10044         PetscInt       v;
10045 
10046         for (v = 0; v < numFaceVertices; ++v) {
10047           if (subfaceVertices[v] == p) break;
10048         }
10049         if (v == numFaceVertices) break;
10050       }
10051       if (d == dof) {
10052         numFaces = 1;
10053         ((PetscInt *) faces)[0] = f;
10054       }
10055     }
10056   }
10057 #endif
10058   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
10059   else if (numFaces == 1) {
10060     /* Add the other cell neighbor for this face */
10061     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
10062   } else {
10063     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
10064     PetscBool posOriented;
10065 
10066     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10067     origVertices = &orientedVertices[numFaceVertices];
10068     indices      = &orientedVertices[numFaceVertices*2];
10069     orientedSubVertices = &orientedVertices[numFaceVertices*3];
10070     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
10071     /* TODO: I know that routine should return a permutation, not the indices */
10072     for (v = 0; v < numFaceVertices; ++v) {
10073       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
10074       for (ov = 0; ov < numFaceVertices; ++ov) {
10075         if (orientedVertices[ov] == vertex) {
10076           orientedSubVertices[ov] = subvertex;
10077           break;
10078         }
10079       }
10080       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
10081     }
10082     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
10083     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
10084     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10085     ++(*newFacePoint);
10086   }
10087   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10088   PetscFunctionReturn(0);
10089 }
10090 
10091 #undef __FUNCT__
10092 #define __FUNCT__ "DMPlexCreateSubmesh"
10093 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
10094 {
10095   MPI_Comm        comm = ((PetscObject) dm)->comm;
10096   DM_Plex     *submesh;
10097   PetscBool       boundaryFaces = PETSC_FALSE;
10098   PetscSection    coordSection, subCoordSection;
10099   Vec             coordinates, subCoordinates;
10100   PetscScalar    *coords, *subCoords;
10101   IS              labelIS;
10102   const PetscInt *subVertices;
10103   PetscInt       *subVerticesActive, *tmpPoints;
10104   PetscInt       *subCells = PETSC_NULL;
10105   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
10106   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
10107   PetscInt        dim; /* Right now, do not specify dimension */
10108   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
10109   PetscErrorCode  ierr;
10110 
10111   PetscFunctionBegin;
10112   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10113   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10114   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10115   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
10116   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10117   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10118   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10119   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10120   subface = &face[maxConeSize];
10121   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
10122   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10123   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10124   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
10125   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
10126   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
10127   maxSubCells = numSubVertices;
10128   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
10129   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
10130   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
10131   for (v = 0; v < numSubVertices; ++v) {
10132     const PetscInt vertex = subVertices[v];
10133     PetscInt *star = PETSC_NULL;
10134     PetscInt  starSize, numCells = 0;
10135 
10136     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10137     for (p = 0; p < starSize*2; p += 2) {
10138       const PetscInt point = star[p];
10139       if ((point >= cStart) && (point < cEnd)) {
10140         star[numCells++] = point;
10141       }
10142     }
10143     numOldSubCells = numSubCells;
10144     for (c = 0; c < numCells; ++c) {
10145       const PetscInt cell    = star[c];
10146       PetscInt      *closure = PETSC_NULL;
10147       PetscInt       closureSize, numCorners = 0, faceSize = 0;
10148       PetscInt       cellLoc;
10149 
10150       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
10151       if (cellLoc >= 0) continue;
10152       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10153       for (p = 0; p < closureSize*2; p += 2) {
10154         const PetscInt point = closure[p];
10155         if ((point >= vStart) && (point < vEnd)) {
10156           closure[numCorners++] = point;
10157         }
10158       }
10159       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
10160       for (corner = 0; corner < numCorners; ++corner) {
10161         const PetscInt cellVertex = closure[corner];
10162         PetscInt       subVertex;
10163 
10164         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
10165         if (subVertex >= 0) { /* contains submesh vertex */
10166           for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10167           if (i == faceSize) {
10168             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
10169             face[faceSize]    = cellVertex;
10170             subface[faceSize] = subVertex;
10171             ++faceSize;
10172           }
10173         }
10174       }
10175       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10176       if (faceSize >= nFV) {
10177         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10178         if (numSubCells >= maxSubCells) {
10179           PetscInt *tmpCells;
10180           maxSubCells *= 2;
10181           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
10182           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
10183           ierr = PetscFree(subCells);CHKERRQ(ierr);
10184           subCells = tmpCells;
10185         }
10186         /* TOOD: Maybe overestimate then squeeze out empty faces */
10187         if (faceSize > nFV) {
10188           /* TODO: This is tricky. Maybe just add all faces */
10189           numSubFaces++;
10190         } else {
10191           numSubFaces++;
10192         }
10193         for (f = 0; f < faceSize; ++f) {
10194           subVerticesActive[subface[f]] = 1;
10195         }
10196         subCells[numSubCells++] = cell;
10197       }
10198     }
10199     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10200     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
10201   }
10202   /* Pick out active subvertices */
10203   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
10204     if (subVerticesActive[v]) {
10205       subVerticesActive[numSubVerticesActive++] = subVertices[v];
10206     }
10207   }
10208   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
10209   /* Set cone sizes */
10210   firstSubVertex = numSubCells;
10211   firstSubFace   = numSubCells+numSubVerticesActive;
10212   newFacePoint   = firstSubFace;
10213   for (c = 0; c < numSubCells; ++c) {
10214     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
10215   }
10216   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
10217     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
10218   }
10219   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
10220   /* Create face cones */
10221   for (c = 0; c < numSubCells; ++c) {
10222     const PetscInt cell    = subCells[c];
10223     PetscInt      *closure = PETSC_NULL;
10224     PetscInt       closureSize, numCorners = 0, faceSize = 0;
10225 
10226     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10227     for (p = 0; p < closureSize*2; p += 2) {
10228       const PetscInt point = closure[p];
10229       if ((point >= vStart) && (point < vEnd)) {
10230         closure[numCorners++] = point;
10231       }
10232     }
10233     for (corner = 0; corner < numCorners; ++corner) {
10234       const PetscInt cellVertex = closure[corner];
10235       PetscInt       subVertex;
10236 
10237       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
10238       if (subVertex >= 0) { /* contains submesh vertex */
10239         for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10240         if (i == faceSize) {
10241           face[faceSize]    = cellVertex;
10242           subface[faceSize] = numSubCells+subVertex;
10243           ++faceSize;
10244         }
10245       }
10246     }
10247     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10248     if (faceSize >= nFV) {
10249       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10250       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
10251       /*   We have to take all the faces, and discard those in the interior */
10252       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
10253 #if 0
10254       /* This object just calls insert on each face that comes from subsets() */
10255       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
10256       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
10257       PointArray                          faceVec(face->begin(), face->end());
10258 
10259       subsets(faceVec, nFV, inserter);
10260 #endif
10261       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10262     }
10263   }
10264   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
10265   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
10266   /* Build coordinates */
10267   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10268   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10269   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
10270   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10271   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10272     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10273   }
10274   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10275   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10276   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
10277   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10278   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10279   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10280   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10281   for (v = 0; v < numSubVerticesActive; ++v) {
10282     const PetscInt vertex    = subVerticesActive[v];
10283     const PetscInt subVertex = firstSubVertex+v;
10284     PetscInt dof, off, sdof, soff;
10285 
10286     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10287     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10288     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10289     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10290     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10291     for (d = 0; d < dof; ++d) {
10292       subCoords[soff+d] = coords[off+d];
10293     }
10294   }
10295   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10296   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10297   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
10298   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10299 
10300   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
10301   /* Create map from submesh points to original mesh points */
10302   submesh = (DM_Plex *) (*subdm)->data;
10303   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10304   for (c = 0; c < numSubCells; ++c) {
10305     tmpPoints[c] = subCells[c];
10306   }
10307   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
10308     tmpPoints[v] = subVerticesActive[v-numSubCells];
10309   }
10310   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
10311 
10312   ierr = PetscFree(subCells);CHKERRQ(ierr);
10313   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10314   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10315   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10316   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10317   PetscFunctionReturn(0);
10318 }
10319 
10320 #undef __FUNCT__
10321 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10322 /* We can easily have a form that takes an IS instead */
10323 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10324 {
10325   PetscSection   section, globalSection;
10326   PetscInt      *numbers, p;
10327   PetscErrorCode ierr;
10328 
10329   PetscFunctionBegin;
10330   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10331   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10332   for (p = pStart; p < pEnd; ++p) {
10333     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10334   }
10335   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10336   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10337   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10338   for (p = pStart; p < pEnd; ++p) {
10339     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10340   }
10341   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10342   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10343   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10344   PetscFunctionReturn(0);
10345 }
10346 
10347 #undef __FUNCT__
10348 #define __FUNCT__ "DMPlexGetCellNumbering"
10349 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10350 {
10351   DM_Plex    *mesh = (DM_Plex *) dm->data;
10352   PetscInt       cellHeight, cStart, cEnd, cMax;
10353   PetscErrorCode ierr;
10354 
10355   PetscFunctionBegin;
10356   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10357   if (!mesh->globalCellNumbers) {
10358     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10359     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10360     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10361     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10362     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10363   }
10364   *globalCellNumbers = mesh->globalCellNumbers;
10365   PetscFunctionReturn(0);
10366 }
10367 
10368 #undef __FUNCT__
10369 #define __FUNCT__ "DMPlexGetVertexNumbering"
10370 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10371 {
10372   DM_Plex    *mesh = (DM_Plex *) dm->data;
10373   PetscInt       vStart, vEnd, vMax;
10374   PetscErrorCode ierr;
10375 
10376   PetscFunctionBegin;
10377   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10378   if (!mesh->globalVertexNumbers) {
10379     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10380     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10381     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10382     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10383   }
10384   *globalVertexNumbers = mesh->globalVertexNumbers;
10385   PetscFunctionReturn(0);
10386 }
10387 
10388 #undef __FUNCT__
10389 #define __FUNCT__ "DMPlexGetSubpointMap"
10390 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10391 {
10392   DM_Plex *mesh = (DM_Plex *) dm->data;
10393 
10394   PetscFunctionBegin;
10395   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10396   PetscValidPointer(subpointMap, 2);
10397   *subpointMap = mesh->subpointMap;
10398   PetscFunctionReturn(0);
10399 }
10400 
10401 #undef __FUNCT__
10402 #define __FUNCT__ "DMPlexSetSubpointMap"
10403 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10404 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10405 {
10406   DM_Plex *mesh = (DM_Plex *) dm->data;
10407 
10408   PetscFunctionBegin;
10409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10410   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10411   mesh->subpointMap = subpointMap;
10412   PetscFunctionReturn(0);
10413 }
10414 
10415 #undef __FUNCT__
10416 #define __FUNCT__ "DMPlexGetScale"
10417 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10418 {
10419   DM_Plex *mesh = (DM_Plex *) dm->data;
10420 
10421   PetscFunctionBegin;
10422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10423   PetscValidPointer(scale, 3);
10424   *scale = mesh->scale[unit];
10425   PetscFunctionReturn(0);
10426 }
10427 
10428 #undef __FUNCT__
10429 #define __FUNCT__ "DMPlexSetScale"
10430 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10431 {
10432   DM_Plex *mesh = (DM_Plex *) dm->data;
10433 
10434   PetscFunctionBegin;
10435   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10436   mesh->scale[unit] = scale;
10437   PetscFunctionReturn(0);
10438 }
10439 
10440 
10441 /*******************************************************************************
10442 This should be in a separate Discretization object, but I am not sure how to lay
10443 it out yet, so I am stuffing things here while I experiment.
10444 *******************************************************************************/
10445 #undef __FUNCT__
10446 #define __FUNCT__ "DMPlexSetFEMIntegration"
10447 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10448                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10449                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10450                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10451                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10452                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10453                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10454                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10455                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10456                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10457                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10458                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], 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 {
10465   DM_Plex *mesh = (DM_Plex *) dm->data;
10466 
10467   PetscFunctionBegin;
10468   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10469   mesh->integrateResidualFEM       = integrateResidualFEM;
10470   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10471   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10472   PetscFunctionReturn(0);
10473 }
10474 
10475 #undef __FUNCT__
10476 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10477 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10478 {
10479   Vec            coordinates;
10480   PetscSection   section, cSection;
10481   PetscInt       dim, vStart, vEnd, v, c, d;
10482   PetscScalar   *values, *cArray;
10483   PetscReal     *coords;
10484   PetscErrorCode ierr;
10485 
10486   PetscFunctionBegin;
10487   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10488   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10489   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10490   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10491   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10492   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10493   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10494   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10495   for (v = vStart; v < vEnd; ++v) {
10496     PetscInt dof, off;
10497 
10498     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10499     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10500     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10501     for (d = 0; d < dof; ++d) {
10502       coords[d] = PetscRealPart(cArray[off+d]);
10503     }
10504     for (c = 0; c < numComp; ++c) {
10505       values[c] = (*funcs[c])(coords);
10506     }
10507     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10508   }
10509   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10510   /* Temporary, must be replaced by a projection on the finite element basis */
10511   {
10512     PetscInt eStart = 0, eEnd = 0, e, depth;
10513 
10514     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10515     --depth;
10516     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10517     for (e = eStart; e < eEnd; ++e) {
10518       const PetscInt *cone = PETSC_NULL;
10519       PetscInt        coneSize, d;
10520       PetscScalar    *coordsA, *coordsB;
10521 
10522       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10523       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10524       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10525       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10526       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10527       for (d = 0; d < dim; ++d) {
10528         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10529       }
10530       for (c = 0; c < numComp; ++c) {
10531         values[c] = (*funcs[c])(coords);
10532       }
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) {
10760       u[c*cellDof+i] = x[i];
10761     }
10762     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10763   }
10764   for (field = 0; field < numFields; ++field) {
10765     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10766     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10767     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10768     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10769     /* Conforming batches */
10770     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10771     PetscInt numBlocks  = 1;
10772     PetscInt batchSize  = numBlocks * blockSize;
10773     PetscInt numBatches = numBatchesTmp;
10774     PetscInt numChunks  = numCells / (numBatches*batchSize);
10775     /* Remainder */
10776     PetscInt numRemainder = numCells % (numBatches * batchSize);
10777     PetscInt offset       = numCells - numRemainder;
10778 
10779     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10780     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10781                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10782   }
10783   for (c = cStart; c < cEnd; ++c) {
10784     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10785     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10786   }
10787   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10788   if (mesh->printFEM) {
10789     PetscMPIInt rank, numProcs;
10790     PetscInt    p;
10791 
10792     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10793     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10794     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10795     for (p = 0; p < numProcs; ++p) {
10796       if (p == rank) {
10797         Vec f;
10798 
10799         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10800         ierr = VecCopy(F, f);CHKERRQ(ierr);
10801         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10802         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10803         ierr = VecDestroy(&f);CHKERRQ(ierr);
10804         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10805       }
10806       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10807     }
10808   }
10809   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10810   PetscFunctionReturn(0);
10811 }
10812 
10813 #undef __FUNCT__
10814 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10815 /*@C
10816   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10817 
10818   Input Parameters:
10819 + dm - The mesh
10820 . J  - The Jacobian shell matrix
10821 . X  - Local input vector
10822 - user - The user context
10823 
10824   Output Parameter:
10825 . F  - Local output vector
10826 
10827   Note:
10828   The second member of the user context must be an FEMContext.
10829 
10830   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10831   like a GPU, or vectorize on a multicore machine.
10832 
10833 .seealso: DMPlexComputeResidualFEM()
10834 */
10835 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10836 {
10837   DM_Plex      *mesh = (DM_Plex *) dm->data;
10838   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10839   PetscQuadrature *quad = fem->quad;
10840   PetscSection     section;
10841   JacActionCtx    *jctx;
10842   PetscReal       *v0, *J, *invJ, *detJ;
10843   PetscScalar     *elemVec, *u, *a;
10844   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10845   PetscInt         cellDof = 0;
10846   PetscErrorCode   ierr;
10847 
10848   PetscFunctionBegin;
10849   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10850   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10851   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10852   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10853   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10854   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10855   numCells = cEnd - cStart;
10856   for (field = 0; field < numFields; ++field) {
10857     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10858   }
10859   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10860   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);
10861   for (c = cStart; c < cEnd; ++c) {
10862     const PetscScalar *x;
10863     PetscInt           i;
10864 
10865     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10866     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10867     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10868     for (i = 0; i < cellDof; ++i) {
10869       u[c*cellDof+i] = x[i];
10870     }
10871     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10872     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10873     for (i = 0; i < cellDof; ++i) {
10874       a[c*cellDof+i] = x[i];
10875     }
10876     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10877   }
10878   for (field = 0; field < numFields; ++field) {
10879     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10880     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10881     /* Conforming batches */
10882     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10883     PetscInt numBlocks  = 1;
10884     PetscInt batchSize  = numBlocks * blockSize;
10885     PetscInt numBatches = numBatchesTmp;
10886     PetscInt numChunks  = numCells / (numBatches*batchSize);
10887     /* Remainder */
10888     PetscInt numRemainder = numCells % (numBatches * batchSize);
10889     PetscInt offset       = numCells - numRemainder;
10890 
10891     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);
10892     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],
10893                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10894   }
10895   for (c = cStart; c < cEnd; ++c) {
10896     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10897     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10898   }
10899   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10900   if (mesh->printFEM) {
10901     PetscMPIInt rank, numProcs;
10902     PetscInt    p;
10903 
10904     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10905     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10906     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10907     for (p = 0; p < numProcs; ++p) {
10908       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10909       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10910     }
10911   }
10912   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10913   PetscFunctionReturn(0);
10914 }
10915 
10916 #undef __FUNCT__
10917 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10918 /*@
10919   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10920 
10921   Input Parameters:
10922 + dm - The mesh
10923 . X  - Local input vector
10924 - user - The user context
10925 
10926   Output Parameter:
10927 . Jac  - Jacobian matrix
10928 
10929   Note:
10930   The second member of the user context must be an FEMContext.
10931 
10932   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10933   like a GPU, or vectorize on a multicore machine.
10934 
10935 .seealso: FormFunctionLocal()
10936 */
10937 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10938 {
10939   DM_Plex      *mesh = (DM_Plex *) dm->data;
10940   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10941   PetscQuadrature *quad = fem->quad;
10942   PetscSection     section;
10943   PetscReal       *v0, *J, *invJ, *detJ;
10944   PetscScalar     *elemMat, *u;
10945   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10946   PetscInt         cellDof = 0, numComponents = 0;
10947   PetscBool        isShell;
10948   PetscErrorCode   ierr;
10949 
10950   PetscFunctionBegin;
10951   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10952   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10953   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10954   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10955   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10956   numCells = cEnd - cStart;
10957   for (field = 0; field < numFields; ++field) {
10958     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10959     numComponents += quad[field].numComponents;
10960   }
10961   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10962   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10963   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);
10964   for (c = cStart; c < cEnd; ++c) {
10965     const PetscScalar *x;
10966     PetscInt           i;
10967 
10968     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10969     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10970     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10971 
10972     for (i = 0; i < cellDof; ++i) {
10973       u[c*cellDof+i] = x[i];
10974     }
10975     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10976   }
10977   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10978   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10979     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10980     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10981     PetscInt       fieldJ;
10982 
10983     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10984       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10985       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10986       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10987       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10988       /* Conforming batches */
10989       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10990       PetscInt numBlocks  = 1;
10991       PetscInt batchSize  = numBlocks * blockSize;
10992       PetscInt numBatches = numBatchesTmp;
10993       PetscInt numChunks  = numCells / (numBatches*batchSize);
10994       /* Remainder */
10995       PetscInt numRemainder = numCells % (numBatches * batchSize);
10996       PetscInt offset       = numCells - numRemainder;
10997 
10998       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10999       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
11000                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
11001     }
11002   }
11003   for (c = cStart; c < cEnd; ++c) {
11004     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
11005     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
11006   }
11007   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
11008 
11009   /* Assemble matrix, using the 2-step process:
11010        MatAssemblyBegin(), MatAssemblyEnd(). */
11011   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11012   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11013 
11014   if (mesh->printFEM) {
11015     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
11016     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
11017     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
11018   }
11019   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11020   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
11021   if (isShell) {
11022     JacActionCtx *jctx;
11023 
11024     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
11025     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
11026   }
11027   *str = SAME_NONZERO_PATTERN;
11028   PetscFunctionReturn(0);
11029 }
11030 
11031 
11032 #undef __FUNCT__
11033 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
11034 /*@C
11035   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
11036   the local section and an SF describing the section point overlap.
11037 
11038   Input Parameters:
11039   + s - The PetscSection for the local field layout
11040   . sf - The SF describing parallel layout of the section points
11041   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
11042   . label - The label specifying the points
11043   - labelValue - The label stratum specifying the points
11044 
11045   Output Parameter:
11046   . gsection - The PetscSection for the global field layout
11047 
11048   Note: This gives negative sizes and offsets to points not owned by this process
11049 
11050   Level: developer
11051 
11052 .seealso: PetscSectionCreate()
11053 @*/
11054 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
11055 {
11056   PetscInt      *neg;
11057   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
11058   PetscErrorCode ierr;
11059 
11060   PetscFunctionBegin;
11061   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
11062   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
11063   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
11064   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
11065   /* Mark ghost points with negative dof */
11066   for (p = pStart; p < pEnd; ++p) {
11067     PetscInt value;
11068 
11069     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11070     if (value != labelValue) continue;
11071     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11072     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11073     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11074     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11075     neg[p-pStart] = -(dof+1);
11076   }
11077   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11078   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11079   if (nroots >= 0) {
11080     if (nroots > pEnd - pStart) {
11081       PetscInt *tmpDof;
11082       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11083       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11084       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11085       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11086       for (p = pStart; p < pEnd; ++p) {
11087         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
11088       }
11089       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11090     } else {
11091       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11092       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11093     }
11094   }
11095   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11096   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11097     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11098     (*gsection)->atlasOff[p] = off;
11099     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11100   }
11101   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11102   globalOff -= off;
11103   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11104     (*gsection)->atlasOff[p] += globalOff;
11105     neg[p] = -((*gsection)->atlasOff[p]+1);
11106   }
11107   /* Put in negative offsets for ghost points */
11108   if (nroots >= 0) {
11109     if (nroots > pEnd - pStart) {
11110       PetscInt *tmpOff;
11111       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11112       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11113       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11114       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11115       for (p = pStart; p < pEnd; ++p) {
11116         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
11117       }
11118       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11119     } else {
11120       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11121       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11122     }
11123   }
11124   ierr = PetscFree(neg);CHKERRQ(ierr);
11125   PetscFunctionReturn(0);
11126 }
11127