xref: /petsc/src/dm/impls/plex/plex.c (revision 2fa5cd679192b9b390e47ae2d0650965e6b1d9fa)
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             /* Split old face:   Replace negative side cell with cohesive cell */
4066             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4067           } else {
4068             /* Split new face:   Replace positive side cell with cohesive cell */
4069             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4070           }
4071         }
4072       } else if (dep == 0) {
4073         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4074 
4075         /* Split old vertex: Edges in old split faces and new cohesive edge */
4076         for(e = 0, q = 0; e < supportSize; ++e) {
4077           PetscInt val;
4078 
4079           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4080           if ((val == 1) || (val == (shift + 1))) {
4081             supportNew[q++] = depthOffset[1] + support[e];
4082           }
4083         }
4084         supportNew[q] = cedge;
4085         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4086         /* Split new vertex: Edges in new split faces and new cohesive edge */
4087         for(e = 0, q = 0; e < supportSize; ++e) {
4088           PetscInt val, edge;
4089 
4090           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4091           if (val == 1) {
4092             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4093             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4094             supportNew[q++] = pMaxNew[1] + edge;
4095           } else if (val == -(shift + 1)) {
4096             supportNew[q++] = depthOffset[1] + support[e];
4097           }
4098         }
4099         supportNew[q] = cedge;
4100         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4101         /* Cohesive edge:    Old and new split vertex, punting on support */
4102         coneNew[0] = newp;
4103         coneNew[1] = splitp;
4104         ierr = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4105       } else if (dep == dim-2) {
4106         /* Split old edge:   old vertices in cone so no change */
4107         /* Split new edge:   new vertices in cone */
4108         for(q = 0; q < coneSize; ++q) {
4109           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4110           coneNew[q] = pMaxNew[dim-3] + v;
4111         }
4112         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4113         /* Split old edge: Faces in positive side cells and old split faces */
4114         for(e = 0, q = 0; e < supportSize; ++e) {
4115           PetscInt val;
4116 
4117           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4118           if ((val == dim-1) || (val == (shift + dim-1))) {
4119             supportNew[q++] = depthOffset[dim-1] + support[e];
4120           }
4121         }
4122         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4123         /* Split new edge: Faces in negative side cells and new split faces */
4124         for(e = 0, q = 0; e < supportSize; ++e) {
4125           PetscInt val, face;
4126 
4127           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4128           if (val == dim-1) {
4129             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4130             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4131             supportNew[q++] = pMaxNew[dim-1] + face;
4132           } else if (val == -(shift + dim-1)) {
4133             supportNew[q++] = depthOffset[dim-1] + support[e];
4134           }
4135         }
4136         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4137       }
4138     }
4139   }
4140   /* Step 6b: Replace split points in negative side cones */
4141   for(sp = 0; sp < numSP; ++sp) {
4142     PetscInt        dep = values[sp];
4143     IS              pIS;
4144     PetscInt        numPoints;
4145     const PetscInt *points;
4146 
4147     if (dep >= 0) continue;
4148     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4149     if (!pIS) continue;
4150     dep  = -dep - shift;
4151     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4152     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4153     for(p = 0; p < numPoints; ++p) {
4154       const PetscInt  oldp   = points[p];
4155       const PetscInt  newp   = depthOffset[dep] + oldp;
4156       const PetscInt *cone;
4157       PetscInt        coneSize, c;
4158       PetscBool       replaced = PETSC_FALSE;
4159 
4160       /* Negative edge: replace split vertex */
4161       /* Negative cell: replace split face */
4162       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4163       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4164       for(c = 0; c < coneSize; ++c) {
4165         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4166         PetscInt       csplitp, cp, val;
4167 
4168         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4169         if (val == dep-1) {
4170           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4171           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4172           csplitp = pMaxNew[dep-1] + cp;
4173           ierr = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4174           replaced = PETSC_TRUE;
4175         }
4176       }
4177       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4178     }
4179     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4180     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4181   }
4182   /* Step 7: Stratify */
4183   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4184   /* Step 8: Coordinates */
4185   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4186   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4187   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4188   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4189   for(v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4190     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4191     const PetscInt splitp = pMaxNew[0] + v;
4192     PetscInt       dof, off, soff, d;
4193 
4194     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4195     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4196     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4197     for(d = 0; d < dof; ++d) {
4198       coords[soff+d] = coords[off+d];
4199     }
4200   }
4201   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4202   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4203   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4204   /* Step 10: Labels */
4205   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4206   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4207   for (dep = 0; dep <= depth; ++dep) {
4208     for (p = 0; p < numSplitPoints[dep]; ++p) {
4209       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4210       const PetscInt splitp = pMaxNew[dep] + p;
4211       PetscInt       l;
4212 
4213       for (l = 0; l < numLabels; ++l) {
4214         DMLabel     label;
4215         const char *lname;
4216         PetscInt    val;
4217 
4218         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4219         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4220         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4221         if (val >= 0) {
4222           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4223           if (dep == 0) {
4224             const PetscInt cedge  = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4225             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4226           }
4227         }
4228       }
4229     }
4230   }
4231   for (sp = 0; sp < numSP; ++sp) {
4232     const PetscInt dep = values[sp];
4233 
4234     if ((dep < 0) || (dep > depth)) continue;
4235     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4236     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4237   }
4238   if (label) {
4239     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4240     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4241   }
4242   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4243   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4244   PetscFunctionReturn(0);
4245 }
4246 
4247 #undef __FUNCT__
4248 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4249 /*@C
4250   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4251 
4252   Collective on dm
4253 
4254   Input Parameters:
4255 + dm - The original DM
4256 - labelName - The label specifying the boundary faces (this could be auto-generated)
4257 
4258   Output Parameters:
4259 - dmSplit - The new DM
4260 
4261   Level: developer
4262 
4263 .seealso: DMCreate()
4264 */
4265 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4266 {
4267   DM             sdm;
4268   PetscInt       dim;
4269   PetscErrorCode ierr;
4270 
4271   PetscFunctionBegin;
4272   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4273   PetscValidPointer(dmSplit, 4);
4274   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4275   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4276   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4277   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4278   switch(dim) {
4279   case 2:
4280   case 3:
4281     ierr = DMPlexConstructCohesiveCells_Private(dm, labelName, sdm);CHKERRQ(ierr);
4282     break;
4283   default:
4284     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4285   }
4286   *dmSplit = sdm;
4287   PetscFunctionReturn(0);
4288 }
4289 
4290 #undef __FUNCT__
4291 #define __FUNCT__ "DMLabelCohesiveComplete"
4292 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4293 {
4294   IS              dimIS;
4295   const PetscInt *points;
4296   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4297   PetscErrorCode  ierr;
4298 
4299   PetscFunctionBegin;
4300   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4301   /* Cell orientation for face gives the side of the fault */
4302   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4303   if (!dimIS) PetscFunctionReturn(0);
4304   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4305   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4306   for(p = 0; p < numPoints; ++p) {
4307     const PetscInt *support;
4308     PetscInt        supportSize, s;
4309 
4310     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4311     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4312     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4313     for(s = 0; s < supportSize; ++s) {
4314       const PetscInt *cone, *ornt;
4315       PetscInt        coneSize, c;
4316       PetscBool       pos = PETSC_TRUE;
4317 
4318       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4319       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4320       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4321       for(c = 0; c < coneSize; ++c) {
4322         if (cone[c] == points[p]) {
4323           if (ornt[c] >= 0) {
4324             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4325           } else {
4326             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4327             pos  = PETSC_FALSE;
4328           }
4329           break;
4330         }
4331       }
4332       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]);
4333       /* Put faces touching the fault in the label */
4334       for(c = 0; c < coneSize; ++c) {
4335         const PetscInt point = cone[c];
4336 
4337         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4338         if (val == -1) {
4339           PetscInt *closure = PETSC_NULL;
4340           PetscInt  closureSize, cl;
4341 
4342           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4343           for (cl = 0; cl < closureSize*2; cl += 2) {
4344             const PetscInt clp = closure[cl];
4345 
4346             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4347             if ((val >= 0) && (val < dim-1)) {
4348               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4349               break;
4350             }
4351           }
4352           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4353         }
4354       }
4355     }
4356   }
4357   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4358   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4359   /* Search for other cells/faces/edges connected to the fault by a vertex */
4360   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4361   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4362   if (!dimIS) PetscFunctionReturn(0);
4363   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4364   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4365   for(p = 0; p < numPoints; ++p) {
4366     PetscInt *star = PETSC_NULL;
4367     PetscInt  starSize, s;
4368     PetscInt  again = 1; /* 0: Finished 1: Keep iterating after a change 2: No change */
4369 
4370     /* First mark cells connected to the fault */
4371     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4372     while (again) {
4373       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4374       again = 0;
4375       for (s = 0; s < starSize*2; s += 2) {
4376         const PetscInt  point = star[s];
4377         const PetscInt *cone;
4378         PetscInt        coneSize, c;
4379 
4380         if ((point < cStart) || (point >= cEnd)) continue;
4381         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4382         if (val != -1) continue;
4383         again = 2;
4384         ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4385         ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4386         for(c = 0; c < coneSize; ++c) {
4387           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4388           if (val != -1) {
4389             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);
4390             if (val > 0) {
4391               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4392             } else {
4393               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4394             }
4395             again = 1;
4396             break;
4397           }
4398         }
4399       }
4400     }
4401     /* Classify the rest by cell membership */
4402     for (s = 0; s < starSize*2; s += 2) {
4403       const PetscInt point = star[s];
4404 
4405       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4406       if (val == -1) {
4407         PetscInt *sstar = PETSC_NULL;
4408         PetscInt  sstarSize, ss;
4409         PetscBool marked = PETSC_FALSE;
4410 
4411         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4412         for (ss = 0; ss < sstarSize*2; ss += 2) {
4413           const PetscInt spoint = sstar[ss];
4414 
4415           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4416           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4417           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4418           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4419           if (val > 0) {
4420             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4421           } else {
4422             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4423           }
4424           marked = PETSC_TRUE;
4425           break;
4426         }
4427         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4428         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4429       }
4430     }
4431     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4432   }
4433   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4434   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4435   PetscFunctionReturn(0);
4436 }
4437 
4438 #undef __FUNCT__
4439 #define __FUNCT__ "DMPlexInterpolate_2D"
4440 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4441 {
4442   DM             idm;
4443   DM_Plex       *mesh;
4444   PetscHashIJ    edgeTable;
4445   PetscInt      *off;
4446   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4447   PetscInt       numEdges, firstEdge, edge, e;
4448   PetscErrorCode ierr;
4449 
4450   PetscFunctionBegin;
4451   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4452   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4453   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4454   numCells    = cEnd - cStart;
4455   numVertices = vEnd - vStart;
4456   firstEdge   = numCells + numVertices;
4457   numEdges    = 0 ;
4458   /* Count edges using algorithm from CreateNeighborCSR */
4459   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4460   if (off) {
4461     PetscInt numCorners = 0;
4462 
4463     numEdges = off[numCells]/2;
4464 #if 0
4465     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4466     numEdges += 3*numCells - off[numCells];
4467 #else
4468     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4469     for (c = cStart; c < cEnd; ++c) {
4470       PetscInt coneSize;
4471 
4472       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4473       numCorners += coneSize;
4474     }
4475     numEdges += numCorners - off[numCells];
4476 #endif
4477   }
4478 #if 0
4479   /* Check Euler characteristic V - E + F = 1 */
4480   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4481 #endif
4482   /* Create interpolated mesh */
4483   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4484   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4485   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4486   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4487   for (c = 0; c < numCells; ++c) {
4488     PetscInt numCorners;
4489 
4490     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4491     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4492   }
4493   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4494     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4495   }
4496   ierr = DMSetUp(idm);CHKERRQ(ierr);
4497   /* Get edge cones from subsets of cell vertices */
4498   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4499   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4500 
4501   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4502     const PetscInt *cellFaces;
4503     PetscInt        numCellFaces, faceSize, cf;
4504 
4505     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4506     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4507     for (cf = 0; cf < numCellFaces; ++cf) {
4508 #if 1
4509       PetscHashIJKey key;
4510 
4511       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4512       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4513       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4514       if (e < 0) {
4515         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4516         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4517         e    = edge++;
4518       }
4519 #else
4520       PetscBool found = PETSC_FALSE;
4521 
4522       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4523       for (e = firstEdge; e < edge; ++e) {
4524         const PetscInt *cone;
4525 
4526         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4527         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4528             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4529           found = PETSC_TRUE;
4530           break;
4531         }
4532       }
4533       if (!found) {
4534         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4535         ++edge;
4536       }
4537 #endif
4538       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4539     }
4540   }
4541   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4542   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4543   ierr = PetscFree(off);CHKERRQ(ierr);
4544   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4545   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4546   mesh = (DM_Plex *) (idm)->data;
4547   /* Orient edges */
4548   for (c = 0; c < numCells; ++c) {
4549     const PetscInt *cone = PETSC_NULL, *cellFaces;
4550     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4551 
4552     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4553     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4554     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4555     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4556     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4557     for (cf = 0; cf < numCellFaces; ++cf) {
4558       const PetscInt *econe = PETSC_NULL;
4559       PetscInt        esize;
4560 
4561       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4562       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4563       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]);
4564       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4565         /* Correctly oriented */
4566         mesh->coneOrientations[coff+cf] = 0;
4567       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4568         /* Start at index 1, and reverse orientation */
4569         mesh->coneOrientations[coff+cf] = -(1+1);
4570       }
4571     }
4572   }
4573   *dmInt  = idm;
4574   PetscFunctionReturn(0);
4575 }
4576 
4577 #undef __FUNCT__
4578 #define __FUNCT__ "DMPlexInterpolate_3D"
4579 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4580 {
4581   DM             idm, fdm;
4582   DM_Plex    *mesh;
4583   PetscInt      *off;
4584   const PetscInt numCorners = 4;
4585   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4586   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4587   PetscErrorCode ierr;
4588 
4589   PetscFunctionBegin;
4590   {
4591     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4592     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4593     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4594   }
4595   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4596   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4597   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4598   numCells    = cEnd - cStart;
4599   numVertices = vEnd - vStart;
4600   firstFace   = numCells + numVertices;
4601   numFaces    = 0 ;
4602   /* Count faces using algorithm from CreateNeighborCSR */
4603   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4604   if (off) {
4605     numFaces = off[numCells]/2;
4606     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4607     numFaces += 4*numCells - off[numCells];
4608   }
4609   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4610   firstEdge = firstFace + numFaces;
4611   numEdges  = numVertices + numFaces - numCells - 1;
4612   /* Create interpolated mesh */
4613   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4614   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4615   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4616   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4617   for (c = 0; c < numCells; ++c) {
4618     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4619   }
4620   for (f = firstFace; f < firstFace+numFaces; ++f) {
4621     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4622   }
4623   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4624     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4625   }
4626   ierr = DMSetUp(idm);CHKERRQ(ierr);
4627   /* Get face cones from subsets of cell vertices */
4628   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4629   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4630   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4631   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4632   for (f = firstFace; f < firstFace+numFaces; ++f) {
4633     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4634   }
4635   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4636   for (c = 0, face = firstFace; c < numCells; ++c) {
4637     const PetscInt *cellFaces;
4638     PetscInt        numCellFaces, faceSize, cf;
4639 
4640     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4641     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4642     for (cf = 0; cf < numCellFaces; ++cf) {
4643       PetscBool found = PETSC_FALSE;
4644 
4645       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4646       for (f = firstFace; f < face; ++f) {
4647         const PetscInt *cone = PETSC_NULL;
4648 
4649         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4650         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4651             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4652             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4653             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4654             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4655             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4656           found = PETSC_TRUE;
4657           break;
4658         }
4659       }
4660       if (!found) {
4661         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4662         /* Save the vertices for orientation calculation */
4663         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4664         ++face;
4665       }
4666       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4667     }
4668   }
4669   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4670   /* Get edge cones from subsets of face vertices */
4671   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4672     const PetscInt *cellFaces;
4673     PetscInt        numCellFaces, faceSize, cf;
4674 
4675     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4676     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4677     for (cf = 0; cf < numCellFaces; ++cf) {
4678       PetscBool found = PETSC_FALSE;
4679 
4680       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4681       for (e = firstEdge; e < edge; ++e) {
4682         const PetscInt *cone = PETSC_NULL;
4683 
4684         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4685         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4686             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4687           found = PETSC_TRUE;
4688           break;
4689         }
4690       }
4691       if (!found) {
4692         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4693         ++edge;
4694       }
4695       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4696     }
4697   }
4698   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4699   ierr = PetscFree(off);CHKERRQ(ierr);
4700   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4701   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4702   mesh = (DM_Plex *) (idm)->data;
4703   /* Orient edges */
4704   for (f = firstFace; f < firstFace+numFaces; ++f) {
4705     const PetscInt *cone, *cellFaces;
4706     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4707 
4708     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4709     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4710     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4711     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4712     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4713     for (cf = 0; cf < numCellFaces; ++cf) {
4714       const PetscInt *econe;
4715       PetscInt        esize;
4716 
4717       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4718       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4719       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]);
4720       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4721         /* Correctly oriented */
4722         mesh->coneOrientations[coff+cf] = 0;
4723       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4724         /* Start at index 1, and reverse orientation */
4725         mesh->coneOrientations[coff+cf] = -(1+1);
4726       }
4727     }
4728   }
4729   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4730   /* Orient faces */
4731   for (c = 0; c < numCells; ++c) {
4732     const PetscInt *cone, *cellFaces;
4733     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4734 
4735     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4736     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4737     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4738     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4739     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4740     for (cf = 0; cf < numCellFaces; ++cf) {
4741       PetscInt *origClosure = PETSC_NULL, *closure;
4742       PetscInt  closureSize, i;
4743 
4744       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4745       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4746       for (i = 4; i < 7; ++i) {
4747         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);
4748       }
4749       closure = &origClosure[4*2];
4750       /* Remember that this is the orientation for edges, not vertices */
4751       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4752         /* Correctly oriented */
4753         mesh->coneOrientations[coff+cf] = 0;
4754       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4755         /* Shifted by 1 */
4756         mesh->coneOrientations[coff+cf] = 1;
4757       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4758         /* Shifted by 2 */
4759         mesh->coneOrientations[coff+cf] = 2;
4760       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4761         /* Start at edge 1, and reverse orientation */
4762         mesh->coneOrientations[coff+cf] = -(1+1);
4763       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4764         /* Start at index 0, and reverse orientation */
4765         mesh->coneOrientations[coff+cf] = -(0+1);
4766       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4767         /* Start at index 2, and reverse orientation */
4768         mesh->coneOrientations[coff+cf] = -(2+1);
4769       } 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);
4770       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4771     }
4772   }
4773   {
4774     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4775     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4776     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4777   }
4778   *dmInt  = idm;
4779   PetscFunctionReturn(0);
4780 }
4781 
4782 #undef __FUNCT__
4783 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4784 /*
4785   This takes as input the common mesh generator output, a list of the vertices for each cell
4786 */
4787 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4788 {
4789   PetscInt      *cone, c, p;
4790   PetscErrorCode ierr;
4791 
4792   PetscFunctionBegin;
4793   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4794   for (c = 0; c < numCells; ++c) {
4795     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4796   }
4797   ierr = DMSetUp(dm);CHKERRQ(ierr);
4798   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4799   for (c = 0; c < numCells; ++c) {
4800     for (p = 0; p < numCorners; ++p) {
4801       cone[p] = cells[c*numCorners+p]+numCells;
4802     }
4803     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4804   }
4805   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4806   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4807   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4808   PetscFunctionReturn(0);
4809 }
4810 
4811 #undef __FUNCT__
4812 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4813 /*
4814   This takes as input the coordinates for each vertex
4815 */
4816 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4817 {
4818   PetscSection   coordSection;
4819   Vec            coordinates;
4820   PetscScalar   *coords;
4821   PetscInt       coordSize, v, d;
4822   PetscErrorCode ierr;
4823 
4824   PetscFunctionBegin;
4825   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4826   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4827   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4828   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4829   for (v = numCells; v < numCells+numVertices; ++v) {
4830     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4831     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4832   }
4833   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4834   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4835   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4836   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4837   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4838   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4839   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4840   for (v = 0; v < numVertices; ++v) {
4841     for (d = 0; d < spaceDim; ++d) {
4842       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4843     }
4844   }
4845   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4846   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4847   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4848   PetscFunctionReturn(0);
4849 }
4850 
4851 #undef __FUNCT__
4852 #define __FUNCT__ "DMPlexCreateFromCellList"
4853 /*
4854   This takes as input the common mesh generator output, a list of the vertices for each cell
4855 */
4856 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4857 {
4858   PetscErrorCode ierr;
4859 
4860   PetscFunctionBegin;
4861   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4862   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4863   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4864   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4865   if (interpolate) {
4866     DM idm;
4867 
4868     switch (dim) {
4869     case 2:
4870       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4871     case 3:
4872       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4873     default:
4874       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4875     }
4876     ierr = DMDestroy(dm);CHKERRQ(ierr);
4877     *dm  = idm;
4878   }
4879   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4880   PetscFunctionReturn(0);
4881 }
4882 
4883 #if defined(PETSC_HAVE_TRIANGLE)
4884 #include <triangle.h>
4885 
4886 #undef __FUNCT__
4887 #define __FUNCT__ "InitInput_Triangle"
4888 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4889 {
4890   PetscFunctionBegin;
4891   inputCtx->numberofpoints = 0;
4892   inputCtx->numberofpointattributes = 0;
4893   inputCtx->pointlist = PETSC_NULL;
4894   inputCtx->pointattributelist = PETSC_NULL;
4895   inputCtx->pointmarkerlist = PETSC_NULL;
4896   inputCtx->numberofsegments = 0;
4897   inputCtx->segmentlist = PETSC_NULL;
4898   inputCtx->segmentmarkerlist = PETSC_NULL;
4899   inputCtx->numberoftriangleattributes = 0;
4900   inputCtx->trianglelist = PETSC_NULL;
4901   inputCtx->numberofholes = 0;
4902   inputCtx->holelist = PETSC_NULL;
4903   inputCtx->numberofregions = 0;
4904   inputCtx->regionlist = PETSC_NULL;
4905   PetscFunctionReturn(0);
4906 }
4907 
4908 #undef __FUNCT__
4909 #define __FUNCT__ "InitOutput_Triangle"
4910 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4911 {
4912   PetscFunctionBegin;
4913   outputCtx->numberofpoints = 0;
4914   outputCtx->pointlist = PETSC_NULL;
4915   outputCtx->pointattributelist = PETSC_NULL;
4916   outputCtx->pointmarkerlist = PETSC_NULL;
4917   outputCtx->numberoftriangles = 0;
4918   outputCtx->trianglelist = PETSC_NULL;
4919   outputCtx->triangleattributelist = PETSC_NULL;
4920   outputCtx->neighborlist = PETSC_NULL;
4921   outputCtx->segmentlist = PETSC_NULL;
4922   outputCtx->segmentmarkerlist = PETSC_NULL;
4923   outputCtx->numberofedges = 0;
4924   outputCtx->edgelist = PETSC_NULL;
4925   outputCtx->edgemarkerlist = PETSC_NULL;
4926   PetscFunctionReturn(0);
4927 }
4928 
4929 #undef __FUNCT__
4930 #define __FUNCT__ "FiniOutput_Triangle"
4931 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4932 {
4933   PetscFunctionBegin;
4934   free(outputCtx->pointmarkerlist);
4935   free(outputCtx->edgelist);
4936   free(outputCtx->edgemarkerlist);
4937   free(outputCtx->trianglelist);
4938   free(outputCtx->neighborlist);
4939   PetscFunctionReturn(0);
4940 }
4941 
4942 #undef __FUNCT__
4943 #define __FUNCT__ "DMPlexGenerate_Triangle"
4944 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4945 {
4946   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4947   PetscInt             dim              = 2;
4948   const PetscBool      createConvexHull = PETSC_FALSE;
4949   const PetscBool      constrained      = PETSC_FALSE;
4950   struct triangulateio in;
4951   struct triangulateio out;
4952   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4953   PetscMPIInt          rank;
4954   PetscErrorCode       ierr;
4955 
4956   PetscFunctionBegin;
4957   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4958   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4959   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4960   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4961   in.numberofpoints = vEnd - vStart;
4962   if (in.numberofpoints > 0) {
4963     PetscSection coordSection;
4964     Vec          coordinates;
4965     PetscScalar *array;
4966 
4967     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4968     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4969     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4970     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4971     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4972     for (v = vStart; v < vEnd; ++v) {
4973       const PetscInt idx = v - vStart;
4974       PetscInt       off, d;
4975 
4976       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4977       for (d = 0; d < dim; ++d) {
4978         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4979       }
4980       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4981     }
4982     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4983   }
4984   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4985   in.numberofsegments = eEnd - eStart;
4986   if (in.numberofsegments > 0) {
4987     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4988     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4989     for (e = eStart; e < eEnd; ++e) {
4990       const PetscInt  idx = e - eStart;
4991       const PetscInt *cone;
4992 
4993       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4994       in.segmentlist[idx*2+0] = cone[0] - vStart;
4995       in.segmentlist[idx*2+1] = cone[1] - vStart;
4996       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4997     }
4998   }
4999 #if 0 /* Do not currently support holes */
5000   PetscReal *holeCoords;
5001   PetscInt   h, d;
5002 
5003   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5004   if (in.numberofholes > 0) {
5005     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5006     for (h = 0; h < in.numberofholes; ++h) {
5007       for (d = 0; d < dim; ++d) {
5008         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5009       }
5010     }
5011   }
5012 #endif
5013   if (!rank) {
5014     char args[32];
5015 
5016     /* Take away 'Q' for verbose output */
5017     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5018     if (createConvexHull) {
5019       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5020     }
5021     if (constrained) {
5022       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5023     }
5024     triangulate(args, &in, &out, PETSC_NULL);
5025   }
5026   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5027   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5028   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5029   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5030   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5031 
5032   {
5033     const PetscInt numCorners  = 3;
5034     const PetscInt numCells    = out.numberoftriangles;
5035     const PetscInt numVertices = out.numberofpoints;
5036     const int     *cells       = out.trianglelist;
5037     const double  *meshCoords  = out.pointlist;
5038 
5039     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5040     /* Set labels */
5041     for (v = 0; v < numVertices; ++v) {
5042       if (out.pointmarkerlist[v]) {
5043         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5044       }
5045     }
5046     if (interpolate) {
5047       for (e = 0; e < out.numberofedges; e++) {
5048         if (out.edgemarkerlist[e]) {
5049           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5050           const PetscInt *edges;
5051           PetscInt        numEdges;
5052 
5053           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5054           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5055           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5056           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5057         }
5058       }
5059     }
5060     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5061   }
5062 #if 0 /* Do not currently support holes */
5063   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5064 #endif
5065   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5066   PetscFunctionReturn(0);
5067 }
5068 
5069 #undef __FUNCT__
5070 #define __FUNCT__ "DMPlexRefine_Triangle"
5071 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5072 {
5073   MPI_Comm             comm = ((PetscObject) dm)->comm;
5074   PetscInt             dim  = 2;
5075   struct triangulateio in;
5076   struct triangulateio out;
5077   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5078   PetscMPIInt          rank;
5079   PetscErrorCode       ierr;
5080 
5081   PetscFunctionBegin;
5082   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5083   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5084   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5085   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5086   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5087   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5088   in.numberofpoints = vEnd - vStart;
5089   if (in.numberofpoints > 0) {
5090     PetscSection coordSection;
5091     Vec          coordinates;
5092     PetscScalar *array;
5093 
5094     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5095     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5096     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5097     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5098     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5099     for (v = vStart; v < vEnd; ++v) {
5100       const PetscInt idx = v - vStart;
5101       PetscInt       off, d;
5102 
5103       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5104       for (d = 0; d < dim; ++d) {
5105         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5106       }
5107       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5108     }
5109     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5110   }
5111   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5112   in.numberofcorners   = 3;
5113   in.numberoftriangles = cEnd - cStart;
5114   in.trianglearealist  = (double *) maxVolumes;
5115   if (in.numberoftriangles > 0) {
5116     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5117     for (c = cStart; c < cEnd; ++c) {
5118       const PetscInt idx     = c - cStart;
5119       PetscInt      *closure = PETSC_NULL;
5120       PetscInt       closureSize;
5121 
5122       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5123       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5124       for (v = 0; v < 3; ++v) {
5125         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5126       }
5127       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5128     }
5129   }
5130   /* TODO: Segment markers are missing on input */
5131 #if 0 /* Do not currently support holes */
5132   PetscReal *holeCoords;
5133   PetscInt   h, d;
5134 
5135   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5136   if (in.numberofholes > 0) {
5137     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5138     for (h = 0; h < in.numberofholes; ++h) {
5139       for (d = 0; d < dim; ++d) {
5140         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5141       }
5142     }
5143   }
5144 #endif
5145   if (!rank) {
5146     char args[32];
5147 
5148     /* Take away 'Q' for verbose output */
5149     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5150     triangulate(args, &in, &out, PETSC_NULL);
5151   }
5152   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5153   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5154   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5155   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5156   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5157 
5158   {
5159     const PetscInt numCorners  = 3;
5160     const PetscInt numCells    = out.numberoftriangles;
5161     const PetscInt numVertices = out.numberofpoints;
5162     const int     *cells       = out.trianglelist;
5163     const double  *meshCoords  = out.pointlist;
5164     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5165 
5166     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5167     /* Set labels */
5168     for (v = 0; v < numVertices; ++v) {
5169       if (out.pointmarkerlist[v]) {
5170         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5171       }
5172     }
5173     if (interpolate) {
5174       PetscInt e;
5175 
5176       for (e = 0; e < out.numberofedges; e++) {
5177         if (out.edgemarkerlist[e]) {
5178           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5179           const PetscInt *edges;
5180           PetscInt        numEdges;
5181 
5182           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5183           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5184           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5185           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5186         }
5187       }
5188     }
5189     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5190   }
5191 #if 0 /* Do not currently support holes */
5192   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5193 #endif
5194   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5195   PetscFunctionReturn(0);
5196 }
5197 #endif
5198 
5199 #if defined(PETSC_HAVE_TETGEN)
5200 #include <tetgen.h>
5201 #undef __FUNCT__
5202 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5203 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5204 {
5205   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5206   const PetscInt dim  = 3;
5207   ::tetgenio     in;
5208   ::tetgenio     out;
5209   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5210   PetscMPIInt    rank;
5211   PetscErrorCode ierr;
5212 
5213   PetscFunctionBegin;
5214   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5215   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5216   in.numberofpoints = vEnd - vStart;
5217   if (in.numberofpoints > 0) {
5218     PetscSection coordSection;
5219     Vec          coordinates;
5220     PetscScalar *array;
5221 
5222     in.pointlist       = new double[in.numberofpoints*dim];
5223     in.pointmarkerlist = new int[in.numberofpoints];
5224     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5225     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5226     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5227     for (v = vStart; v < vEnd; ++v) {
5228       const PetscInt idx = v - vStart;
5229       PetscInt       off, d;
5230 
5231       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5232       for (d = 0; d < dim; ++d) {
5233         in.pointlist[idx*dim + d] = array[off+d];
5234       }
5235       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5236     }
5237     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5238   }
5239   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5240   in.numberoffacets = fEnd - fStart;
5241   if (in.numberoffacets > 0) {
5242     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5243     in.facetmarkerlist = new int[in.numberoffacets];
5244     for (f = fStart; f < fEnd; ++f) {
5245       const PetscInt idx    = f - fStart;
5246       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5247 
5248       in.facetlist[idx].numberofpolygons = 1;
5249       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5250       in.facetlist[idx].numberofholes    = 0;
5251       in.facetlist[idx].holelist         = NULL;
5252 
5253       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5254       for (p = 0; p < numPoints*2; p += 2) {
5255         const PetscInt point = points[p];
5256         if ((point >= vStart) && (point < vEnd)) {
5257           points[numVertices++] = point;
5258         }
5259       }
5260 
5261       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5262       poly->numberofvertices = numVertices;
5263       poly->vertexlist       = new int[poly->numberofvertices];
5264       for (v = 0; v < numVertices; ++v) {
5265         const PetscInt vIdx = points[v] - vStart;
5266         poly->vertexlist[v] = vIdx;
5267       }
5268       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5269       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5270     }
5271   }
5272   if (!rank) {
5273     char args[32];
5274 
5275     /* Take away 'Q' for verbose output */
5276     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5277     ::tetrahedralize(args, &in, &out);
5278   }
5279   {
5280     const PetscInt numCorners  = 4;
5281     const PetscInt numCells    = out.numberoftetrahedra;
5282     const PetscInt numVertices = out.numberofpoints;
5283     const int     *cells       = out.tetrahedronlist;
5284     const double  *meshCoords  = out.pointlist;
5285 
5286     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5287     /* Set labels */
5288     for (v = 0; v < numVertices; ++v) {
5289       if (out.pointmarkerlist[v]) {
5290         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5291       }
5292     }
5293     if (interpolate) {
5294       PetscInt e;
5295 
5296       for (e = 0; e < out.numberofedges; e++) {
5297         if (out.edgemarkerlist[e]) {
5298           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5299           const PetscInt *edges;
5300           PetscInt        numEdges;
5301 
5302           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5303           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5304           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5305           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5306         }
5307       }
5308       for (f = 0; f < out.numberoftrifaces; f++) {
5309         if (out.trifacemarkerlist[f]) {
5310           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5311           const PetscInt *faces;
5312           PetscInt        numFaces;
5313 
5314           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5315           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5316           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5317           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5318         }
5319       }
5320     }
5321     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5322   }
5323   PetscFunctionReturn(0);
5324 }
5325 
5326 #undef __FUNCT__
5327 #define __FUNCT__ "DMPlexRefine_Tetgen"
5328 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5329 {
5330   MPI_Comm       comm = ((PetscObject) dm)->comm;
5331   const PetscInt dim  = 3;
5332   ::tetgenio     in;
5333   ::tetgenio     out;
5334   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5335   PetscMPIInt    rank;
5336   PetscErrorCode ierr;
5337 
5338   PetscFunctionBegin;
5339   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5340   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5341   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5342   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5343   in.numberofpoints = vEnd - vStart;
5344   if (in.numberofpoints > 0) {
5345     PetscSection coordSection;
5346     Vec          coordinates;
5347     PetscScalar *array;
5348 
5349     in.pointlist       = new double[in.numberofpoints*dim];
5350     in.pointmarkerlist = new int[in.numberofpoints];
5351     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5352     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5353     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5354     for (v = vStart; v < vEnd; ++v) {
5355       const PetscInt idx = v - vStart;
5356       PetscInt       off, d;
5357 
5358       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5359       for (d = 0; d < dim; ++d) {
5360         in.pointlist[idx*dim + d] = array[off+d];
5361       }
5362       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5363     }
5364     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5365   }
5366   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5367   in.numberofcorners       = 4;
5368   in.numberoftetrahedra    = cEnd - cStart;
5369   in.tetrahedronvolumelist = (double *) maxVolumes;
5370   if (in.numberoftetrahedra > 0) {
5371     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5372     for (c = cStart; c < cEnd; ++c) {
5373       const PetscInt idx     = c - cStart;
5374       PetscInt      *closure = PETSC_NULL;
5375       PetscInt       closureSize;
5376 
5377       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5378       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5379       for (v = 0; v < 4; ++v) {
5380         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5381       }
5382       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5383     }
5384   }
5385   /* TODO: Put in boundary faces with markers */
5386   if (!rank) {
5387     char args[32];
5388 
5389     /* Take away 'Q' for verbose output */
5390     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5391     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5392     ::tetrahedralize(args, &in, &out);
5393   }
5394   in.tetrahedronvolumelist = NULL;
5395 
5396   {
5397     const PetscInt numCorners  = 4;
5398     const PetscInt numCells    = out.numberoftetrahedra;
5399     const PetscInt numVertices = out.numberofpoints;
5400     const int     *cells       = out.tetrahedronlist;
5401     const double  *meshCoords  = out.pointlist;
5402     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5403 
5404     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5405     /* Set labels */
5406     for (v = 0; v < numVertices; ++v) {
5407       if (out.pointmarkerlist[v]) {
5408         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5409       }
5410     }
5411     if (interpolate) {
5412       PetscInt e, f;
5413 
5414       for (e = 0; e < out.numberofedges; e++) {
5415         if (out.edgemarkerlist[e]) {
5416           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5417           const PetscInt *edges;
5418           PetscInt        numEdges;
5419 
5420           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5421           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5422           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5423           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5424         }
5425       }
5426       for (f = 0; f < out.numberoftrifaces; f++) {
5427         if (out.trifacemarkerlist[f]) {
5428           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5429           const PetscInt *faces;
5430           PetscInt        numFaces;
5431 
5432           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5433           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5434           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5435           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5436         }
5437       }
5438     }
5439     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5440   }
5441   PetscFunctionReturn(0);
5442 }
5443 #endif
5444 
5445 #if defined(PETSC_HAVE_CTETGEN)
5446 #include "ctetgen.h"
5447 
5448 #undef __FUNCT__
5449 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5450 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5451 {
5452   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5453   const PetscInt dim  = 3;
5454   PLC           *in, *out;
5455   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5456   PetscMPIInt    rank;
5457   PetscErrorCode ierr;
5458 
5459   PetscFunctionBegin;
5460   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5461   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5462   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5463   ierr = PLCCreate(&in);CHKERRQ(ierr);
5464   ierr = PLCCreate(&out);CHKERRQ(ierr);
5465   in->numberofpoints = vEnd - vStart;
5466   if (in->numberofpoints > 0) {
5467     PetscSection coordSection;
5468     Vec          coordinates;
5469     PetscScalar *array;
5470 
5471     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5472     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5473     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5474     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5475     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5476     for (v = vStart; v < vEnd; ++v) {
5477       const PetscInt idx = v - vStart;
5478       PetscInt       off, d, m;
5479 
5480       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5481       for (d = 0; d < dim; ++d) {
5482         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5483       }
5484       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5485       in->pointmarkerlist[idx] = (int) m;
5486     }
5487     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5488   }
5489   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5490   in->numberoffacets = fEnd - fStart;
5491   if (in->numberoffacets > 0) {
5492     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5493     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5494     for (f = fStart; f < fEnd; ++f) {
5495       const PetscInt idx    = f - fStart;
5496       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5497       polygon       *poly;
5498 
5499       in->facetlist[idx].numberofpolygons = 1;
5500       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5501       in->facetlist[idx].numberofholes    = 0;
5502       in->facetlist[idx].holelist         = PETSC_NULL;
5503 
5504       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5505       for (p = 0; p < numPoints*2; p += 2) {
5506         const PetscInt point = points[p];
5507         if ((point >= vStart) && (point < vEnd)) {
5508           points[numVertices++] = point;
5509         }
5510       }
5511 
5512       poly = in->facetlist[idx].polygonlist;
5513       poly->numberofvertices = numVertices;
5514       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5515       for (v = 0; v < numVertices; ++v) {
5516         const PetscInt vIdx = points[v] - vStart;
5517         poly->vertexlist[v] = vIdx;
5518       }
5519       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5520       in->facetmarkerlist[idx] = (int) m;
5521       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5522     }
5523   }
5524   if (!rank) {
5525     TetGenOpts t;
5526 
5527     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5528     t.in        = boundary; /* Should go away */
5529     t.plc       = 1;
5530     t.quality   = 1;
5531     t.edgesout  = 1;
5532     t.zeroindex = 1;
5533     t.quiet     = 1;
5534     t.verbose   = verbose;
5535     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5536     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5537   }
5538   {
5539     const PetscInt numCorners  = 4;
5540     const PetscInt numCells    = out->numberoftetrahedra;
5541     const PetscInt numVertices = out->numberofpoints;
5542     const int     *cells       = out->tetrahedronlist;
5543     const double  *meshCoords  = out->pointlist;
5544 
5545     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5546     /* Set labels */
5547     for (v = 0; v < numVertices; ++v) {
5548       if (out->pointmarkerlist[v]) {
5549         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5550       }
5551     }
5552     if (interpolate) {
5553       PetscInt e;
5554 
5555       for (e = 0; e < out->numberofedges; e++) {
5556         if (out->edgemarkerlist[e]) {
5557           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5558           const PetscInt *edges;
5559           PetscInt        numEdges;
5560 
5561           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5562           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5563           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5564           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5565         }
5566       }
5567       for (f = 0; f < out->numberoftrifaces; f++) {
5568         if (out->trifacemarkerlist[f]) {
5569           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5570           const PetscInt *faces;
5571           PetscInt        numFaces;
5572 
5573           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5574           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5575           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5576           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5577         }
5578       }
5579     }
5580     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5581   }
5582 
5583   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5584   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5585   PetscFunctionReturn(0);
5586 }
5587 
5588 #undef __FUNCT__
5589 #define __FUNCT__ "DMPlexRefine_CTetgen"
5590 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5591 {
5592   MPI_Comm       comm = ((PetscObject) dm)->comm;
5593   const PetscInt dim  = 3;
5594   PLC           *in, *out;
5595   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5596   PetscMPIInt    rank;
5597   PetscErrorCode ierr;
5598 
5599   PetscFunctionBegin;
5600   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5601   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5602   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5603   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5604   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5605   ierr = PLCCreate(&in);CHKERRQ(ierr);
5606   ierr = PLCCreate(&out);CHKERRQ(ierr);
5607   in->numberofpoints = vEnd - vStart;
5608   if (in->numberofpoints > 0) {
5609     PetscSection coordSection;
5610     Vec          coordinates;
5611     PetscScalar *array;
5612 
5613     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5614     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5615     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5616     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5617     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5618     for (v = vStart; v < vEnd; ++v) {
5619       const PetscInt idx = v - vStart;
5620       PetscInt       off, d, m;
5621 
5622       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5623       for (d = 0; d < dim; ++d) {
5624         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5625       }
5626       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5627       in->pointmarkerlist[idx] = (int) m;
5628     }
5629     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5630   }
5631   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5632   in->numberofcorners       = 4;
5633   in->numberoftetrahedra    = cEnd - cStart;
5634   in->tetrahedronvolumelist = maxVolumes;
5635   if (in->numberoftetrahedra > 0) {
5636     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5637     for (c = cStart; c < cEnd; ++c) {
5638       const PetscInt idx     = c - cStart;
5639       PetscInt      *closure = PETSC_NULL;
5640       PetscInt       closureSize;
5641 
5642       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5643       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5644       for (v = 0; v < 4; ++v) {
5645         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5646       }
5647       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5648     }
5649   }
5650   if (!rank) {
5651     TetGenOpts t;
5652 
5653     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5654     t.in        = dm; /* Should go away */
5655     t.refine    = 1;
5656     t.varvolume = 1;
5657     t.quality   = 1;
5658     t.edgesout  = 1;
5659     t.zeroindex = 1;
5660     t.quiet     = 1;
5661     t.verbose   = verbose; /* Change this */
5662     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5663     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5664   }
5665   {
5666     const PetscInt numCorners  = 4;
5667     const PetscInt numCells    = out->numberoftetrahedra;
5668     const PetscInt numVertices = out->numberofpoints;
5669     const int     *cells       = out->tetrahedronlist;
5670     const double  *meshCoords  = out->pointlist;
5671     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5672 
5673     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5674     /* Set labels */
5675     for (v = 0; v < numVertices; ++v) {
5676       if (out->pointmarkerlist[v]) {
5677         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5678       }
5679     }
5680     if (interpolate) {
5681       PetscInt e, f;
5682 
5683       for (e = 0; e < out->numberofedges; e++) {
5684         if (out->edgemarkerlist[e]) {
5685           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5686           const PetscInt *edges;
5687           PetscInt        numEdges;
5688 
5689           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5690           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5691           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5692           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5693         }
5694       }
5695       for (f = 0; f < out->numberoftrifaces; f++) {
5696         if (out->trifacemarkerlist[f]) {
5697           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5698           const PetscInt *faces;
5699           PetscInt        numFaces;
5700 
5701           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5702           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5703           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5704           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5705         }
5706       }
5707     }
5708     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5709   }
5710   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5711   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5712   PetscFunctionReturn(0);
5713 }
5714 #endif
5715 
5716 #undef __FUNCT__
5717 #define __FUNCT__ "DMPlexGenerate"
5718 /*@C
5719   DMPlexGenerate - Generates a mesh.
5720 
5721   Not Collective
5722 
5723   Input Parameters:
5724 + boundary - The DMPlex boundary object
5725 . name - The mesh generation package name
5726 - interpolate - Flag to create intermediate mesh elements
5727 
5728   Output Parameter:
5729 . mesh - The DMPlex object
5730 
5731   Level: intermediate
5732 
5733 .keywords: mesh, elements
5734 .seealso: DMPlexCreate(), DMRefine()
5735 @*/
5736 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5737 {
5738   PetscInt       dim;
5739   char           genname[1024];
5740   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5741   PetscErrorCode ierr;
5742 
5743   PetscFunctionBegin;
5744   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5745   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5746   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5747   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5748   if (flg) {name = genname;}
5749   if (name) {
5750     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5751     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5752     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5753   }
5754   switch (dim) {
5755   case 1:
5756     if (!name || isTriangle) {
5757 #if defined(PETSC_HAVE_TRIANGLE)
5758       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5759 #else
5760       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5761 #endif
5762     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5763     break;
5764   case 2:
5765     if (!name || isCTetgen) {
5766 #if defined(PETSC_HAVE_CTETGEN)
5767       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5768 #else
5769       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5770 #endif
5771     } else if (isTetgen) {
5772 #if defined(PETSC_HAVE_TETGEN)
5773       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5774 #else
5775       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5776 #endif
5777     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5778     break;
5779   default:
5780     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5781   }
5782   PetscFunctionReturn(0);
5783 }
5784 
5785 typedef PetscInt CellRefiner;
5786 
5787 #undef __FUNCT__
5788 #define __FUNCT__ "GetDepthStart_Private"
5789 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5790 {
5791   PetscFunctionBegin;
5792   if (cStart) *cStart = 0;
5793   if (vStart) *vStart = depthSize[depth];
5794   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5795   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5796   PetscFunctionReturn(0);
5797 }
5798 
5799 #undef __FUNCT__
5800 #define __FUNCT__ "GetDepthEnd_Private"
5801 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5802 {
5803   PetscFunctionBegin;
5804   if (cEnd) *cEnd = depthSize[depth];
5805   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5806   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5807   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5808   PetscFunctionReturn(0);
5809 }
5810 
5811 #undef __FUNCT__
5812 #define __FUNCT__ "CellRefinerGetSizes"
5813 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5814 {
5815   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5816   PetscErrorCode ierr;
5817 
5818   PetscFunctionBegin;
5819   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5820   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5821   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5822   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5823   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5824   switch (refiner) {
5825   case 1:
5826     /* Simplicial 2D */
5827     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5828     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5829     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5830     break;
5831   case 3:
5832     /* Hybrid 2D */
5833     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5834     cMax = PetscMin(cEnd, cMax);
5835     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5836     fMax = PetscMin(fEnd, fMax);
5837     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5838     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 */
5839     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5840     break;
5841   case 2:
5842     /* Hex 2D */
5843     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5844     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5845     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5846     break;
5847   default:
5848     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5849   }
5850   PetscFunctionReturn(0);
5851 }
5852 
5853 #undef __FUNCT__
5854 #define __FUNCT__ "CellRefinerSetConeSizes"
5855 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5856 {
5857   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5858   PetscErrorCode ierr;
5859 
5860   PetscFunctionBegin;
5861   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5862   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5863   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5864   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5865   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5866   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5867   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5868   switch (refiner) {
5869   case 1:
5870     /* Simplicial 2D */
5871     /* All cells have 3 faces */
5872     for (c = cStart; c < cEnd; ++c) {
5873       for (r = 0; r < 4; ++r) {
5874         const PetscInt newp = (c - cStart)*4 + r;
5875 
5876         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5877       }
5878     }
5879     /* Split faces have 2 vertices and the same cells as the parent */
5880     for (f = fStart; f < fEnd; ++f) {
5881       for (r = 0; r < 2; ++r) {
5882         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5883         PetscInt       size;
5884 
5885         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5886         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5887         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5888       }
5889     }
5890     /* Interior faces have 2 vertices and 2 cells */
5891     for (c = cStart; c < cEnd; ++c) {
5892       for (r = 0; r < 3; ++r) {
5893         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5894 
5895         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5896         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5897       }
5898     }
5899     /* Old vertices have identical supports */
5900     for (v = vStart; v < vEnd; ++v) {
5901       const PetscInt newp = vStartNew + (v - vStart);
5902       PetscInt       size;
5903 
5904       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5905       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5906     }
5907     /* Face vertices have 2 + cells*2 supports */
5908     for (f = fStart; f < fEnd; ++f) {
5909       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5910       PetscInt       size;
5911 
5912       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5913       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5914     }
5915     break;
5916   case 2:
5917     /* Hex 2D */
5918     /* All cells have 4 faces */
5919     for (c = cStart; c < cEnd; ++c) {
5920       for (r = 0; r < 4; ++r) {
5921         const PetscInt newp = (c - cStart)*4 + r;
5922 
5923         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5924       }
5925     }
5926     /* Split faces have 2 vertices and the same cells as the parent */
5927     for (f = fStart; f < fEnd; ++f) {
5928       for (r = 0; r < 2; ++r) {
5929         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5930         PetscInt       size;
5931 
5932         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5933         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5934         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5935       }
5936     }
5937     /* Interior faces have 2 vertices and 2 cells */
5938     for (c = cStart; c < cEnd; ++c) {
5939       for (r = 0; r < 4; ++r) {
5940         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5941 
5942         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5943         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5944       }
5945     }
5946     /* Old vertices have identical supports */
5947     for (v = vStart; v < vEnd; ++v) {
5948       const PetscInt newp = vStartNew + (v - vStart);
5949       PetscInt       size;
5950 
5951       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5952       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5953     }
5954     /* Face vertices have 2 + cells supports */
5955     for (f = fStart; f < fEnd; ++f) {
5956       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5957       PetscInt       size;
5958 
5959       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5960       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5961     }
5962     /* Cell vertices have 4 supports */
5963     for (c = cStart; c < cEnd; ++c) {
5964       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5965 
5966       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5967     }
5968     break;
5969   case 3:
5970     /* Hybrid 2D */
5971     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5972     cMax = PetscMin(cEnd, cMax);
5973     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5974     fMax = PetscMin(fEnd, fMax);
5975     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5976     /* Interior cells have 3 faces */
5977     for (c = cStart; c < cMax; ++c) {
5978       for (r = 0; r < 4; ++r) {
5979         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5980 
5981         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5982       }
5983     }
5984     /* Hybrid cells have 4 faces */
5985     for (c = cMax; c < cEnd; ++c) {
5986       for (r = 0; r < 2; ++r) {
5987         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5988 
5989         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5990       }
5991     }
5992     /* Interior split faces have 2 vertices and the same cells as the parent */
5993     for (f = fStart; f < fMax; ++f) {
5994       for (r = 0; r < 2; ++r) {
5995         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5996         PetscInt       size;
5997 
5998         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5999         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6000         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6001       }
6002     }
6003     /* Interior cell faces have 2 vertices and 2 cells */
6004     for (c = cStart; c < cMax; ++c) {
6005       for (r = 0; r < 3; ++r) {
6006         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6007 
6008         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6009         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6010       }
6011     }
6012     /* Hybrid faces have 2 vertices and the same cells */
6013     for (f = fMax; f < fEnd; ++f) {
6014       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6015       PetscInt       size;
6016 
6017       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6018       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6019       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6020     }
6021     /* Hybrid cell faces have 2 vertices and 2 cells */
6022     for (c = cMax; c < cEnd; ++c) {
6023       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6024 
6025       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6026       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6027     }
6028     /* Old vertices have identical supports */
6029     for (v = vStart; v < vEnd; ++v) {
6030       const PetscInt newp = vStartNew + (v - vStart);
6031       PetscInt       size;
6032 
6033       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6034       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6035     }
6036     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6037     for (f = fStart; f < fMax; ++f) {
6038       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6039       const PetscInt *support;
6040       PetscInt        size, newSize = 2, s;
6041 
6042       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6043       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6044       for (s = 0; s < size; ++s) {
6045         if (support[s] >= cMax) {
6046           newSize += 1;
6047         } else {
6048           newSize += 2;
6049         }
6050       }
6051       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6052     }
6053     break;
6054   default:
6055     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6056   }
6057   PetscFunctionReturn(0);
6058 }
6059 
6060 #undef __FUNCT__
6061 #define __FUNCT__ "CellRefinerSetCones"
6062 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6063 {
6064   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;
6065   PetscInt       maxSupportSize, *supportRef;
6066   PetscErrorCode ierr;
6067 
6068   PetscFunctionBegin;
6069   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6070   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6071   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6072   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6073   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6074   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6075   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6076   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6077   switch (refiner) {
6078   case 1:
6079     /* Simplicial 2D */
6080     /*
6081      2
6082      |\
6083      | \
6084      |  \
6085      |   \
6086      | C  \
6087      |     \
6088      |      \
6089      2---1---1
6090      |\  D  / \
6091      | 2   0   \
6092      |A \ /  B  \
6093      0---0-------1
6094      */
6095     /* All cells have 3 faces */
6096     for (c = cStart; c < cEnd; ++c) {
6097       const PetscInt  newp = cStartNew + (c - cStart)*4;
6098       const PetscInt *cone, *ornt;
6099       PetscInt        coneNew[3], orntNew[3];
6100 
6101       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6102       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6103       /* A triangle */
6104       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6105       orntNew[0] = ornt[0];
6106       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6107       orntNew[1] = -2;
6108       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6109       orntNew[2] = ornt[2];
6110       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6111       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6112 #if 1
6113       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);
6114       for (p = 0; p < 3; ++p) {
6115         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);
6116       }
6117 #endif
6118       /* B triangle */
6119       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6120       orntNew[0] = ornt[0];
6121       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6122       orntNew[1] = ornt[1];
6123       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6124       orntNew[2] = -2;
6125       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6126       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6127 #if 1
6128       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);
6129       for (p = 0; p < 3; ++p) {
6130         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);
6131       }
6132 #endif
6133       /* C triangle */
6134       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6135       orntNew[0] = -2;
6136       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6137       orntNew[1] = ornt[1];
6138       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6139       orntNew[2] = ornt[2];
6140       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6141       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6142 #if 1
6143       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);
6144       for (p = 0; p < 3; ++p) {
6145         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);
6146       }
6147 #endif
6148       /* D triangle */
6149       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6150       orntNew[0] = 0;
6151       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6152       orntNew[1] = 0;
6153       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6154       orntNew[2] = 0;
6155       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6156       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6157 #if 1
6158       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);
6159       for (p = 0; p < 3; ++p) {
6160         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);
6161       }
6162 #endif
6163     }
6164     /* Split faces have 2 vertices and the same cells as the parent */
6165     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6166     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6167     for (f = fStart; f < fEnd; ++f) {
6168       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6169 
6170       for (r = 0; r < 2; ++r) {
6171         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6172         const PetscInt *cone, *support;
6173         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6174 
6175         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6176         coneNew[0] = vStartNew + (cone[0] - vStart);
6177         coneNew[1] = vStartNew + (cone[1] - vStart);
6178         coneNew[(r+1)%2] = newv;
6179         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6180 #if 1
6181         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6182         for (p = 0; p < 2; ++p) {
6183           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);
6184         }
6185 #endif
6186         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6187         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6188         for (s = 0; s < supportSize; ++s) {
6189           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6190           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6191           for (c = 0; c < coneSize; ++c) {
6192             if (cone[c] == f) {
6193               break;
6194             }
6195           }
6196           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6197         }
6198         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6199 #if 1
6200         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6201         for (p = 0; p < supportSize; ++p) {
6202           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);
6203         }
6204 #endif
6205       }
6206     }
6207     /* Interior faces have 2 vertices and 2 cells */
6208     for (c = cStart; c < cEnd; ++c) {
6209       const PetscInt *cone;
6210 
6211       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6212       for (r = 0; r < 3; ++r) {
6213         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6214         PetscInt       coneNew[2];
6215         PetscInt       supportNew[2];
6216 
6217         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6218         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6219         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6220 #if 1
6221         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6222         for (p = 0; p < 2; ++p) {
6223           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);
6224         }
6225 #endif
6226         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6227         supportNew[1] = (c - cStart)*4 + 3;
6228         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6229 #if 1
6230         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6231         for (p = 0; p < 2; ++p) {
6232           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);
6233         }
6234 #endif
6235       }
6236     }
6237     /* Old vertices have identical supports */
6238     for (v = vStart; v < vEnd; ++v) {
6239       const PetscInt  newp = vStartNew + (v - vStart);
6240       const PetscInt *support, *cone;
6241       PetscInt        size, s;
6242 
6243       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6244       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6245       for (s = 0; s < size; ++s) {
6246         PetscInt r = 0;
6247 
6248         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6249         if (cone[1] == v) r = 1;
6250         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6251       }
6252       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6253 #if 1
6254       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6255       for (p = 0; p < size; ++p) {
6256         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);
6257       }
6258 #endif
6259     }
6260     /* Face vertices have 2 + cells*2 supports */
6261     for (f = fStart; f < fEnd; ++f) {
6262       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6263       const PetscInt *cone, *support;
6264       PetscInt        size, s;
6265 
6266       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6267       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6268       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6269       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6270       for (s = 0; s < size; ++s) {
6271         PetscInt r = 0;
6272 
6273         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6274         if      (cone[1] == f) r = 1;
6275         else if (cone[2] == f) r = 2;
6276         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6277         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6278       }
6279       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6280 #if 1
6281       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6282       for (p = 0; p < 2+size*2; ++p) {
6283         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);
6284       }
6285 #endif
6286     }
6287     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6288     break;
6289   case 2:
6290     /* Hex 2D */
6291     /*
6292      3---------2---------2
6293      |         |         |
6294      |    D    2    C    |
6295      |         |         |
6296      3----3----0----1----1
6297      |         |         |
6298      |    A    0    B    |
6299      |         |         |
6300      0---------0---------1
6301      */
6302     /* All cells have 4 faces */
6303     for (c = cStart; c < cEnd; ++c) {
6304       const PetscInt  newp = (c - cStart)*4;
6305       const PetscInt *cone, *ornt;
6306       PetscInt        coneNew[4], orntNew[4];
6307 
6308       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6309       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6310       /* A quad */
6311       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6312       orntNew[0] = ornt[0];
6313       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6314       orntNew[1] = 0;
6315       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6316       orntNew[2] = -2;
6317       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6318       orntNew[3] = ornt[3];
6319       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6320       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6321 #if 1
6322       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);
6323       for (p = 0; p < 4; ++p) {
6324         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);
6325       }
6326 #endif
6327       /* B quad */
6328       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6329       orntNew[0] = ornt[0];
6330       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6331       orntNew[1] = ornt[1];
6332       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6333       orntNew[2] = 0;
6334       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6335       orntNew[3] = -2;
6336       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6337       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6338 #if 1
6339       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);
6340       for (p = 0; p < 4; ++p) {
6341         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);
6342       }
6343 #endif
6344       /* C quad */
6345       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6346       orntNew[0] = -2;
6347       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6348       orntNew[1] = ornt[1];
6349       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6350       orntNew[2] = ornt[2];
6351       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6352       orntNew[3] = 0;
6353       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6354       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6355 #if 1
6356       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);
6357       for (p = 0; p < 4; ++p) {
6358         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);
6359       }
6360 #endif
6361       /* D quad */
6362       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6363       orntNew[0] = 0;
6364       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6365       orntNew[1] = -2;
6366       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6367       orntNew[2] = ornt[2];
6368       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6369       orntNew[3] = ornt[3];
6370       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6371       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6372 #if 1
6373       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);
6374       for (p = 0; p < 4; ++p) {
6375         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);
6376       }
6377 #endif
6378     }
6379     /* Split faces have 2 vertices and the same cells as the parent */
6380     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6381     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6382     for (f = fStart; f < fEnd; ++f) {
6383       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6384 
6385       for (r = 0; r < 2; ++r) {
6386         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6387         const PetscInt *cone, *support;
6388         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6389 
6390         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6391         coneNew[0] = vStartNew + (cone[0] - vStart);
6392         coneNew[1] = vStartNew + (cone[1] - vStart);
6393         coneNew[(r+1)%2] = newv;
6394         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6395 #if 1
6396         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6397         for (p = 0; p < 2; ++p) {
6398           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);
6399         }
6400 #endif
6401         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6402         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6403         for (s = 0; s < supportSize; ++s) {
6404           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6405           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6406           for (c = 0; c < coneSize; ++c) {
6407             if (cone[c] == f) {
6408               break;
6409             }
6410           }
6411           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6412         }
6413         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6414 #if 1
6415         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6416         for (p = 0; p < supportSize; ++p) {
6417           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);
6418         }
6419 #endif
6420       }
6421     }
6422     /* Interior faces have 2 vertices and 2 cells */
6423     for (c = cStart; c < cEnd; ++c) {
6424       const PetscInt *cone;
6425       PetscInt        coneNew[2], supportNew[2];
6426 
6427       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6428       for (r = 0; r < 4; ++r) {
6429         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6430 
6431         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6432         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6433         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6434 #if 1
6435         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6436         for (p = 0; p < 2; ++p) {
6437           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);
6438         }
6439 #endif
6440         supportNew[0] = (c - cStart)*4 + r;
6441         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6442         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6443 #if 1
6444         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6445         for (p = 0; p < 2; ++p) {
6446           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);
6447         }
6448 #endif
6449       }
6450     }
6451     /* Old vertices have identical supports */
6452     for (v = vStart; v < vEnd; ++v) {
6453       const PetscInt  newp = vStartNew + (v - vStart);
6454       const PetscInt *support, *cone;
6455       PetscInt        size, s;
6456 
6457       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6458       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6459       for (s = 0; s < size; ++s) {
6460         PetscInt r = 0;
6461 
6462         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6463         if (cone[1] == v) r = 1;
6464         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6465       }
6466       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6467 #if 1
6468       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6469       for (p = 0; p < size; ++p) {
6470         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);
6471       }
6472 #endif
6473     }
6474     /* Face vertices have 2 + cells supports */
6475     for (f = fStart; f < fEnd; ++f) {
6476       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6477       const PetscInt *cone, *support;
6478       PetscInt        size, s;
6479 
6480       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6481       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6482       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6483       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6484       for (s = 0; s < size; ++s) {
6485         PetscInt r = 0;
6486 
6487         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6488         if      (cone[1] == f) r = 1;
6489         else if (cone[2] == f) r = 2;
6490         else if (cone[3] == f) r = 3;
6491         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6492       }
6493       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6494 #if 1
6495       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6496       for (p = 0; p < 2+size; ++p) {
6497         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);
6498       }
6499 #endif
6500     }
6501     /* Cell vertices have 4 supports */
6502     for (c = cStart; c < cEnd; ++c) {
6503       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6504       PetscInt       supportNew[4];
6505 
6506       for (r = 0; r < 4; ++r) {
6507         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6508       }
6509       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6510     }
6511     break;
6512   case 3:
6513     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6514     cMax = PetscMin(cEnd, cMax);
6515     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6516     fMax = PetscMin(fEnd, fMax);
6517     /* Interior cells have 3 faces */
6518     for (c = cStart; c < cMax; ++c) {
6519       const PetscInt  newp = cStartNew + (c - cStart)*4;
6520       const PetscInt *cone, *ornt;
6521       PetscInt        coneNew[3], orntNew[3];
6522 
6523       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6524       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6525       /* A triangle */
6526       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6527       orntNew[0] = ornt[0];
6528       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6529       orntNew[1] = -2;
6530       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6531       orntNew[2] = ornt[2];
6532       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6533       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6534 #if 1
6535       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);
6536       for (p = 0; p < 3; ++p) {
6537         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);
6538       }
6539 #endif
6540       /* B triangle */
6541       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6542       orntNew[0] = ornt[0];
6543       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6544       orntNew[1] = ornt[1];
6545       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6546       orntNew[2] = -2;
6547       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6548       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6549 #if 1
6550       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);
6551       for (p = 0; p < 3; ++p) {
6552         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);
6553       }
6554 #endif
6555       /* C triangle */
6556       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6557       orntNew[0] = -2;
6558       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6559       orntNew[1] = ornt[1];
6560       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6561       orntNew[2] = ornt[2];
6562       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6563       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6564 #if 1
6565       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);
6566       for (p = 0; p < 3; ++p) {
6567         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);
6568       }
6569 #endif
6570       /* D triangle */
6571       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6572       orntNew[0] = 0;
6573       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6574       orntNew[1] = 0;
6575       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6576       orntNew[2] = 0;
6577       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6578       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6579 #if 1
6580       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);
6581       for (p = 0; p < 3; ++p) {
6582         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);
6583       }
6584 #endif
6585     }
6586     /*
6587      2----3----3
6588      |         |
6589      |    B    |
6590      |         |
6591      0----4--- 1
6592      |         |
6593      |    A    |
6594      |         |
6595      0----2----1
6596      */
6597     /* Hybrid cells have 4 faces */
6598     for (c = cMax; c < cEnd; ++c) {
6599       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6600       const PetscInt *cone, *ornt;
6601       PetscInt        coneNew[4], orntNew[4];
6602 
6603       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6604       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6605       /* A quad */
6606       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6607       orntNew[0] = ornt[0];
6608       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6609       orntNew[1] = ornt[1];
6610       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6611       orntNew[2] = 0;
6612       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6613       orntNew[3] = 0;
6614       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6615       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6616 #if 1
6617       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);
6618       for (p = 0; p < 4; ++p) {
6619         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);
6620       }
6621 #endif
6622       /* B quad */
6623       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6624       orntNew[0] = ornt[0];
6625       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6626       orntNew[1] = ornt[1];
6627       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6628       orntNew[2] = 0;
6629       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6630       orntNew[3] = 0;
6631       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6632       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6633 #if 1
6634       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);
6635       for (p = 0; p < 4; ++p) {
6636         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);
6637       }
6638 #endif
6639     }
6640     /* Interior split faces have 2 vertices and the same cells as the parent */
6641     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6642     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6643     for (f = fStart; f < fMax; ++f) {
6644       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6645 
6646       for (r = 0; r < 2; ++r) {
6647         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6648         const PetscInt *cone, *support;
6649         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6650 
6651         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6652         coneNew[0] = vStartNew + (cone[0] - vStart);
6653         coneNew[1] = vStartNew + (cone[1] - vStart);
6654         coneNew[(r+1)%2] = newv;
6655         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6656 #if 1
6657         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6658         for (p = 0; p < 2; ++p) {
6659           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);
6660         }
6661 #endif
6662         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6663         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6664         for (s = 0; s < supportSize; ++s) {
6665           if (support[s] >= cMax) {
6666             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6667           } else {
6668             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6669             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6670             for (c = 0; c < coneSize; ++c) {
6671               if (cone[c] == f) {
6672                 break;
6673               }
6674             }
6675             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6676           }
6677         }
6678         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6679 #if 1
6680         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6681         for (p = 0; p < supportSize; ++p) {
6682           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);
6683         }
6684 #endif
6685       }
6686     }
6687     /* Interior cell faces have 2 vertices and 2 cells */
6688     for (c = cStart; c < cMax; ++c) {
6689       const PetscInt *cone;
6690 
6691       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6692       for (r = 0; r < 3; ++r) {
6693         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6694         PetscInt       coneNew[2];
6695         PetscInt       supportNew[2];
6696 
6697         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6698         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6699         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6700 #if 1
6701         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6702         for (p = 0; p < 2; ++p) {
6703           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);
6704         }
6705 #endif
6706         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6707         supportNew[1] = (c - cStart)*4 + 3;
6708         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6709 #if 1
6710         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6711         for (p = 0; p < 2; ++p) {
6712           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);
6713         }
6714 #endif
6715       }
6716     }
6717     /* Interior hybrid faces have 2 vertices and the same cells */
6718     for (f = fMax; f < fEnd; ++f) {
6719       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6720       const PetscInt *cone;
6721       const PetscInt *support;
6722       PetscInt        coneNew[2];
6723       PetscInt        supportNew[2];
6724       PetscInt        size, s, r;
6725 
6726       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6727       coneNew[0] = vStartNew + (cone[0] - vStart);
6728       coneNew[1] = vStartNew + (cone[1] - vStart);
6729       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6730 #if 1
6731       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6732       for (p = 0; p < 2; ++p) {
6733         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);
6734       }
6735 #endif
6736       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6737       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6738       for (s = 0; s < size; ++s) {
6739         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6740         for (r = 0; r < 2; ++r) {
6741           if (cone[r+2] == f) break;
6742         }
6743         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6744       }
6745       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6746 #if 1
6747       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6748       for (p = 0; p < size; ++p) {
6749         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);
6750       }
6751 #endif
6752     }
6753     /* Cell hybrid faces have 2 vertices and 2 cells */
6754     for (c = cMax; c < cEnd; ++c) {
6755       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6756       const PetscInt *cone;
6757       PetscInt        coneNew[2];
6758       PetscInt        supportNew[2];
6759 
6760       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6761       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6762       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6763       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6764 #if 1
6765       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6766       for (p = 0; p < 2; ++p) {
6767         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);
6768       }
6769 #endif
6770       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6771       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6772       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6773 #if 1
6774       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6775       for (p = 0; p < 2; ++p) {
6776         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);
6777       }
6778 #endif
6779     }
6780     /* Old vertices have identical supports */
6781     for (v = vStart; v < vEnd; ++v) {
6782       const PetscInt  newp = vStartNew + (v - vStart);
6783       const PetscInt *support, *cone;
6784       PetscInt        size, s;
6785 
6786       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6787       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6788       for (s = 0; s < size; ++s) {
6789         if (support[s] >= fMax) {
6790           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6791         } else {
6792           PetscInt r = 0;
6793 
6794           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6795           if (cone[1] == v) r = 1;
6796           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6797         }
6798       }
6799       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6800 #if 1
6801       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6802       for (p = 0; p < size; ++p) {
6803         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);
6804       }
6805 #endif
6806     }
6807     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6808     for (f = fStart; f < fMax; ++f) {
6809       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6810       const PetscInt *cone, *support;
6811       PetscInt        size, newSize = 2, s;
6812 
6813       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6814       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6815       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6816       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6817       for (s = 0; s < size; ++s) {
6818         PetscInt r = 0;
6819 
6820         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6821         if (support[s] >= cMax) {
6822           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6823           newSize += 1;
6824         } else {
6825           if      (cone[1] == f) r = 1;
6826           else if (cone[2] == f) r = 2;
6827           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6828           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6829           newSize += 2;
6830         }
6831       }
6832       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6833 #if 1
6834       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6835       for (p = 0; p < newSize; ++p) {
6836         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);
6837       }
6838 #endif
6839     }
6840     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6841     break;
6842   default:
6843     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6844   }
6845   PetscFunctionReturn(0);
6846 }
6847 
6848 #undef __FUNCT__
6849 #define __FUNCT__ "CellRefinerSetCoordinates"
6850 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6851 {
6852   PetscSection   coordSection, coordSectionNew;
6853   Vec            coordinates, coordinatesNew;
6854   PetscScalar   *coords, *coordsNew;
6855   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6856   PetscErrorCode ierr;
6857 
6858   PetscFunctionBegin;
6859   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6860   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6861   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6862   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6863   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6864   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6865   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6866   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6867   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6868   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6869   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6870   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6871   if (fMax < 0) fMax = fEnd;
6872   switch (refiner) {
6873   case 1:
6874   case 2:
6875   case 3:
6876     /* Simplicial and Hex 2D */
6877     /* All vertices have the dim coordinates */
6878     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6879       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6880       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6881     }
6882     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6883     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6884     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6885     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6886     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6887     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6888     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6889     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6890     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6891     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6892     /* Old vertices have the same coordinates */
6893     for (v = vStart; v < vEnd; ++v) {
6894       const PetscInt newv = vStartNew + (v - vStart);
6895       PetscInt       off, offnew, d;
6896 
6897       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6898       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6899       for (d = 0; d < dim; ++d) {
6900         coordsNew[offnew+d] = coords[off+d];
6901       }
6902     }
6903     /* Face vertices have the average of endpoint coordinates */
6904     for (f = fStart; f < fMax; ++f) {
6905       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6906       const PetscInt *cone;
6907       PetscInt        coneSize, offA, offB, offnew, d;
6908 
6909       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6910       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6911       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6912       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6913       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6914       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6915       for (d = 0; d < dim; ++d) {
6916         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6917       }
6918     }
6919     /* Just Hex 2D */
6920     if (refiner == 2) {
6921       /* Cell vertices have the average of corner coordinates */
6922       for (c = cStart; c < cEnd; ++c) {
6923         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6924         PetscInt      *cone = PETSC_NULL;
6925         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6926 
6927         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6928         for (p = 0; p < closureSize*2; p += 2) {
6929           const PetscInt point = cone[p];
6930           if ((point >= vStart) && (point < vEnd)) {
6931             cone[coneSize++] = point;
6932           }
6933         }
6934         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6935         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6936         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6937         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6938         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6939         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6940         for (d = 0; d < dim; ++d) {
6941           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6942         }
6943         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6944       }
6945     }
6946     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6947     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6948     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6949     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6950     break;
6951   default:
6952     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6953   }
6954   PetscFunctionReturn(0);
6955 }
6956 
6957 #undef __FUNCT__
6958 #define __FUNCT__ "DMPlexCreateProcessSF"
6959 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6960 {
6961   PetscInt           numRoots, numLeaves, l;
6962   const PetscInt    *localPoints;
6963   const PetscSFNode *remotePoints;
6964   PetscInt          *localPointsNew;
6965   PetscSFNode       *remotePointsNew;
6966   PetscInt          *ranks, *ranksNew;
6967   PetscErrorCode     ierr;
6968 
6969   PetscFunctionBegin;
6970   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6971   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6972   for (l = 0; l < numLeaves; ++l) {
6973     ranks[l] = remotePoints[l].rank;
6974   }
6975   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6976   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6977   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6978   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6979   for (l = 0; l < numLeaves; ++l) {
6980     ranksNew[l]              = ranks[l];
6981     localPointsNew[l]        = l;
6982     remotePointsNew[l].index = 0;
6983     remotePointsNew[l].rank  = ranksNew[l];
6984   }
6985   ierr = PetscFree(ranks);CHKERRQ(ierr);
6986   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6987   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6988   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6989   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6990   PetscFunctionReturn(0);
6991 }
6992 
6993 #undef __FUNCT__
6994 #define __FUNCT__ "CellRefinerCreateSF"
6995 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6996 {
6997   PetscSF            sf, sfNew, sfProcess;
6998   IS                 processRanks;
6999   MPI_Datatype       depthType;
7000   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7001   const PetscInt    *localPoints, *neighbors;
7002   const PetscSFNode *remotePoints;
7003   PetscInt          *localPointsNew;
7004   PetscSFNode       *remotePointsNew;
7005   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7006   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7007   PetscErrorCode     ierr;
7008 
7009   PetscFunctionBegin;
7010   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7011   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7012   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7013   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7014   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7015   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7016   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7017   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7018   switch (refiner) {
7019   case 3:
7020     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7021     cMax = PetscMin(cEnd, cMax);
7022     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7023     fMax = PetscMin(fEnd, fMax);
7024   }
7025   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7026   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7027   /* Caculate size of new SF */
7028   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7029   if (numRoots < 0) PetscFunctionReturn(0);
7030   for (l = 0; l < numLeaves; ++l) {
7031     const PetscInt p = localPoints[l];
7032 
7033     switch (refiner) {
7034     case 1:
7035       /* Simplicial 2D */
7036       if ((p >= vStart) && (p < vEnd)) {
7037         /* Old vertices stay the same */
7038         ++numLeavesNew;
7039       } else if ((p >= fStart) && (p < fEnd)) {
7040         /* Old faces add new faces and vertex */
7041         numLeavesNew += 1 + 2;
7042       } else if ((p >= cStart) && (p < cEnd)) {
7043         /* Old cells add new cells and interior faces */
7044         numLeavesNew += 4 + 3;
7045       }
7046       break;
7047     case 2:
7048       /* Hex 2D */
7049       if ((p >= vStart) && (p < vEnd)) {
7050         /* Old vertices stay the same */
7051         ++numLeavesNew;
7052       } else if ((p >= fStart) && (p < fEnd)) {
7053         /* Old faces add new faces and vertex */
7054         numLeavesNew += 1 + 2;
7055       } else if ((p >= cStart) && (p < cEnd)) {
7056         /* Old cells add new cells and interior faces */
7057         numLeavesNew += 4 + 4;
7058       }
7059       break;
7060     default:
7061       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7062     }
7063   }
7064   /* Communicate depthSizes for each remote rank */
7065   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7066   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7067   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7068   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);
7069   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7070   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7071   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7072   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7073   for (n = 0; n < numNeighbors; ++n) {
7074     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7075   }
7076   depthSizeOld[depth]   = cMax;
7077   depthSizeOld[0]       = vMax;
7078   depthSizeOld[depth-1] = fMax;
7079   depthSizeOld[1]       = eMax;
7080   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7081   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7082   depthSizeOld[depth]   = cEnd - cStart;
7083   depthSizeOld[0]       = vEnd - vStart;
7084   depthSizeOld[depth-1] = fEnd - fStart;
7085   depthSizeOld[1]       = eEnd - eStart;
7086   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7087   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7088   for (n = 0; n < numNeighbors; ++n) {
7089     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7090   }
7091   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7092   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7093   /* Calculate new point SF */
7094   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7095   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7096   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7097   for (l = 0, m = 0; l < numLeaves; ++l) {
7098     PetscInt    p     = localPoints[l];
7099     PetscInt    rp    = remotePoints[l].index, n;
7100     PetscMPIInt rrank = remotePoints[l].rank;
7101 
7102     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7103     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7104     switch (refiner) {
7105     case 1:
7106       /* Simplicial 2D */
7107       if ((p >= vStart) && (p < vEnd)) {
7108         /* Old vertices stay the same */
7109         localPointsNew[m]        = vStartNew     + (p  - vStart);
7110         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7111         remotePointsNew[m].rank  = rrank;
7112         ++m;
7113       } else if ((p >= fStart) && (p < fEnd)) {
7114         /* Old faces add new faces and vertex */
7115         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7116         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7117         remotePointsNew[m].rank  = rrank;
7118         ++m;
7119         for (r = 0; r < 2; ++r, ++m) {
7120           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7121           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7122           remotePointsNew[m].rank  = rrank;
7123         }
7124       } else if ((p >= cStart) && (p < cEnd)) {
7125         /* Old cells add new cells and interior faces */
7126         for (r = 0; r < 4; ++r, ++m) {
7127           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7128           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7129           remotePointsNew[m].rank  = rrank;
7130         }
7131         for (r = 0; r < 3; ++r, ++m) {
7132           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7133           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7134           remotePointsNew[m].rank  = rrank;
7135         }
7136       }
7137       break;
7138     case 2:
7139       /* Hex 2D */
7140       if ((p >= vStart) && (p < vEnd)) {
7141         /* Old vertices stay the same */
7142         localPointsNew[m]        = vStartNew     + (p  - vStart);
7143         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7144         remotePointsNew[m].rank  = rrank;
7145         ++m;
7146       } else if ((p >= fStart) && (p < fEnd)) {
7147         /* Old faces add new faces and vertex */
7148         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7149         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7150         remotePointsNew[m].rank  = rrank;
7151         ++m;
7152         for (r = 0; r < 2; ++r, ++m) {
7153           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7154           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7155           remotePointsNew[m].rank  = rrank;
7156         }
7157       } else if ((p >= cStart) && (p < cEnd)) {
7158         /* Old cells add new cells and interior faces */
7159         for (r = 0; r < 4; ++r, ++m) {
7160           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7161           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7162           remotePointsNew[m].rank  = rrank;
7163         }
7164         for (r = 0; r < 4; ++r, ++m) {
7165           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7166           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7167           remotePointsNew[m].rank  = rrank;
7168         }
7169       }
7170       break;
7171     case 3:
7172       /* Hybrid simplicial 2D */
7173       if ((p >= vStart) && (p < vEnd)) {
7174         /* Old vertices stay the same */
7175         localPointsNew[m]        = vStartNew     + (p  - vStart);
7176         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7177         remotePointsNew[m].rank  = rrank;
7178         ++m;
7179       } else if ((p >= fStart) && (p < fMax)) {
7180         /* Old interior faces add new faces and vertex */
7181         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7182         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7183         remotePointsNew[m].rank  = rrank;
7184         ++m;
7185         for (r = 0; r < 2; ++r, ++m) {
7186           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7187           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7188           remotePointsNew[m].rank  = rrank;
7189         }
7190       } else if ((p >= fMax) && (p < fEnd)) {
7191         /* Old hybrid faces stay the same */
7192         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7193         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7194         remotePointsNew[m].rank  = rrank;
7195         ++m;
7196       } else if ((p >= cStart) && (p < cMax)) {
7197         /* Old interior cells add new cells and interior faces */
7198         for (r = 0; r < 4; ++r, ++m) {
7199           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7200           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7201           remotePointsNew[m].rank  = rrank;
7202         }
7203         for (r = 0; r < 3; ++r, ++m) {
7204           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7205           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7206           remotePointsNew[m].rank  = rrank;
7207         }
7208       } else if ((p >= cStart) && (p < cMax)) {
7209         /* Old hybrid cells add new cells and hybrid face */
7210         for (r = 0; r < 2; ++r, ++m) {
7211           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7212           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7213           remotePointsNew[m].rank  = rrank;
7214         }
7215         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7216         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]);
7217         remotePointsNew[m].rank  = rrank;
7218         ++m;
7219       }
7220       break;
7221     default:
7222       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7223     }
7224   }
7225   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7226   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7227   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7228   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7229   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7230   PetscFunctionReturn(0);
7231 }
7232 
7233 #undef __FUNCT__
7234 #define __FUNCT__ "CellRefinerCreateLabels"
7235 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7236 {
7237   PetscInt       numLabels, l;
7238   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7239   PetscErrorCode ierr;
7240 
7241   PetscFunctionBegin;
7242   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7243   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7244   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7245   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7246   cStartNew = 0;
7247   vStartNew = depthSize[2];
7248   fStartNew = depthSize[2] + depthSize[0];
7249   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7250   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7251   switch (refiner) {
7252   case 3:
7253     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7254     cMax = PetscMin(cEnd, cMax);
7255     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7256     fMax = PetscMin(fEnd, fMax);
7257   }
7258   for (l = 0; l < numLabels; ++l) {
7259     DMLabel         label, labelNew;
7260     const char     *lname;
7261     PetscBool       isDepth;
7262     IS              valueIS;
7263     const PetscInt *values;
7264     PetscInt        numValues, val;
7265 
7266     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7267     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7268     if (isDepth) continue;
7269     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7270     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7271     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7272     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7273     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7274     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7275     for (val = 0; val < numValues; ++val) {
7276       IS              pointIS;
7277       const PetscInt *points;
7278       PetscInt        numPoints, n;
7279 
7280       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7281       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7282       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7283       for (n = 0; n < numPoints; ++n) {
7284         const PetscInt p = points[n];
7285         switch (refiner) {
7286         case 1:
7287           /* Simplicial 2D */
7288           if ((p >= vStart) && (p < vEnd)) {
7289             /* Old vertices stay the same */
7290             newp = vStartNew + (p - vStart);
7291             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7292           } else if ((p >= fStart) && (p < fEnd)) {
7293             /* Old faces add new faces and vertex */
7294             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7295             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7296             for (r = 0; r < 2; ++r) {
7297               newp = fStartNew + (p - fStart)*2 + r;
7298               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7299             }
7300           } else if ((p >= cStart) && (p < cEnd)) {
7301             /* Old cells add new cells and interior faces */
7302             for (r = 0; r < 4; ++r) {
7303               newp = cStartNew + (p - cStart)*4 + r;
7304               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7305             }
7306             for (r = 0; r < 3; ++r) {
7307               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7308               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7309             }
7310           }
7311           break;
7312         case 2:
7313           /* Hex 2D */
7314           if ((p >= vStart) && (p < vEnd)) {
7315             /* Old vertices stay the same */
7316             newp = vStartNew + (p - vStart);
7317             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7318           } else if ((p >= fStart) && (p < fEnd)) {
7319             /* Old faces add new faces and vertex */
7320             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7321             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7322             for (r = 0; r < 2; ++r) {
7323               newp = fStartNew + (p - fStart)*2 + r;
7324               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7325             }
7326           } else if ((p >= cStart) && (p < cEnd)) {
7327             /* Old cells add new cells and interior faces and vertex */
7328             for (r = 0; r < 4; ++r) {
7329               newp = cStartNew + (p - cStart)*4 + r;
7330               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7331             }
7332             for (r = 0; r < 4; ++r) {
7333               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7334               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7335             }
7336             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7337             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7338           }
7339           break;
7340         case 3:
7341           /* Hybrid simplicial 2D */
7342           if ((p >= vStart) && (p < vEnd)) {
7343             /* Old vertices stay the same */
7344             newp = vStartNew + (p - vStart);
7345             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7346           } else if ((p >= fStart) && (p < fMax)) {
7347             /* Old interior faces add new faces and vertex */
7348             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7349             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7350             for (r = 0; r < 2; ++r) {
7351               newp = fStartNew + (p - fStart)*2 + r;
7352               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7353             }
7354           } else if ((p >= fMax) && (p < fEnd)) {
7355             /* Old hybrid faces stay the same */
7356             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7357             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7358           } else if ((p >= cStart) && (p < cMax)) {
7359             /* Old interior cells add new cells and interior faces */
7360             for (r = 0; r < 4; ++r) {
7361               newp = cStartNew + (p - cStart)*4 + r;
7362               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7363             }
7364             for (r = 0; r < 3; ++r) {
7365               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7366               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7367             }
7368           } else if ((p >= cMax) && (p < cEnd)) {
7369             /* Old hybrid cells add new cells and hybrid face */
7370             for (r = 0; r < 2; ++r) {
7371               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7372               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7373             }
7374             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7375             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7376           }
7377           break;
7378         default:
7379           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7380         }
7381       }
7382       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7383       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7384     }
7385     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7386     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7387     if (0) {
7388       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7389       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7390       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7391     }
7392   }
7393   PetscFunctionReturn(0);
7394 }
7395 
7396 #undef __FUNCT__
7397 #define __FUNCT__ "DMPlexRefine_Uniform"
7398 /* This will only work for interpolated meshes */
7399 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7400 {
7401   DM              rdm;
7402   PetscInt       *depthSize;
7403   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
7404   PetscErrorCode  ierr;
7405 
7406   PetscFunctionBegin;
7407   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7408   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7409   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7410   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7411   /* Calculate number of new points of each depth */
7412   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7413   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7414   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7415   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7416   /* Step 1: Set chart */
7417   for (d = 0; d <= depth; ++d) {
7418     pEnd += depthSize[d];
7419   }
7420   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7421   /* Step 2: Set cone/support sizes */
7422   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7423   /* Step 3: Setup refined DM */
7424   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7425   /* Step 4: Set cones and supports */
7426   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7427   /* Step 5: Stratify */
7428   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7429   /* Step 6: Set coordinates for vertices */
7430   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7431   /* Step 7: Create pointSF */
7432   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7433   /* Step 8: Create labels */
7434   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7435   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7436 
7437   *dmRefined = rdm;
7438 #if 0
7439   DM_Plex *mesh = (DM_Plex *) dm->data;
7440   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7441   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7442 
7443   PetscFunctionBegin;
7444   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7445   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7446   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7447   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7448   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7449 
7450   /* Count number of new cells which are normal and extra */
7451   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7452   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7453   for (c = cStart; c < cEnd2; ++c) {
7454     PetscInt n;
7455     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7456     newNumCellsNormal += n;
7457   }
7458   for (c = cEnd2; c < cEnd; ++c) {
7459     PetscInt n;
7460     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7461     newNumCellsExtra += n;
7462   }
7463   newNumCells = newNumCellsNormal + newNumCellsExtra;
7464   /* Count number of new vertices which are normal and extra */
7465   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7466   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7467   for (c = cStart; c < cEnd; ++c) {
7468     PetscInt *closure = PETSC_NULL;
7469     PetscInt  closureSize, numCorners = 0, p;
7470 
7471     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7472     for (p = 0; p < closureSize*2; p += 2) {
7473       const PetscInt point = closure[p];
7474       if ((point >= vStart) && (point < vEnd)) {
7475         closure[numCorners++] = point;
7476       }
7477     }
7478     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7479     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7480   }
7481   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7482   for (c = cEnd2; c < cEnd; ++c) {
7483     PetscInt *closure = PETSC_NULL;
7484     PetscInt  closureSize, numCorners = 0, p;
7485 
7486     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7487     for (p = 0; p < closureSize*2; p += 2) {
7488       const PetscInt point = closure[p];
7489       if ((point >= vStart) && (point < vEnd)) {
7490         closure[numCorners++] = point;
7491       }
7492     }
7493     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7494     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7495   } /* for */
7496   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7497   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
7498 
7499 #if 1
7500   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
7501   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
7502   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7503   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7504   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7505   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7506   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7507   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7508   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7509   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7510   ierr = PetscSynchronizedFlush(comm);
7511 #endif
7512 
7513   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7514   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7515   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7516   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7517   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7518   /* Set cone and support sizes for new normal cells */
7519   PetscInt newCell = 0;
7520   for (c = cStart; c < cEnd2; ++c) {
7521     PetscInt coneSize, n, i;
7522 
7523     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7524     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7525     for (i = 0; i < n; ++i, ++newCell) {
7526       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7527     }
7528 
7529     PetscInt *closure = PETSC_NULL;
7530     PetscInt  closureSize, numCorners = 0, p;
7531 
7532     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7533     for (p = 0; p < closureSize*2; p += 2) {
7534       const PetscInt point = closure[p];
7535       if ((point >= vStart) && (point < vEnd)) {
7536         closure[numCorners++] = point;
7537       }
7538     }
7539     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7540     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7541   }
7542 
7543   /* Reset current new cell value and loop over censored cells. */
7544   curNewCell = _orderNewMesh->cellsCensored().min();
7545   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7546   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7547     /* Set new cone and support sizes */
7548     cV.clear();
7549     sieve->cone(*c_iter, cV);
7550     const point_type* cone = cV.getPoints();
7551     const int coneSize = cV.getSize();
7552 
7553     const point_type* newCells;
7554     int numNewCells = 0;
7555     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7556 
7557     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7558       newSieve->setConeSize(curNewCell, coneSize);
7559       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7560         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7561       } /* for */
7562     } /* for */
7563   } /* for */
7564   newSieve->allocate();
7565 
7566   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7567 
7568   /* Create refined cells in new sieve. */
7569   curNewCell = _orderNewMesh->cellsNormal().min();
7570   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7571   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7572     cV.clear();
7573     sieve->cone(*c_iter, cV);
7574     const point_type *cone = cV.getPoints();
7575     const int coneSize = cV.getSize();
7576 
7577     const point_type* newCells;
7578     int numNewCells = 0;
7579     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7580 
7581     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7582       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7583     } /* for */
7584   } /* for */
7585   curNewCell = _orderNewMesh->cellsCensored().min();
7586   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7587   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7588     cV.clear();
7589     sieve->cone(*c_iter, cV);
7590     const point_type *cone = cV.getPoints();
7591     const int coneSize = cV.getSize();
7592 
7593     const point_type* newCells;
7594     int numNewCells = 0;
7595     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7596 
7597     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7598       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7599     } /* for */
7600   } /* for */
7601   newSieve->symmetrize();
7602 
7603   /* Set coordinates in refined mesh. */
7604   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7605   assert(!coordinates.isNull());
7606   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7607   assert(!newCoordinates.isNull());
7608 
7609   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7610   assert(vertices->size() > 0);
7611   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7612   assert(spaceDim > 0);
7613   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7614 
7615   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7616   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7617     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7618   } /* for */
7619   newCoordinates->allocatePoint();
7620 
7621   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7622   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7623     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7624     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7625   } /* for */
7626   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7627   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7628     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7629     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7630   } /* for */
7631 
7632   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7633 
7634   /* Create sensored depth */
7635   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7636   assert(!censoredLabel.isNull());
7637 
7638   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7639 
7640   newSieve->roots(depthVisitor);
7641   while (depthVisitor.isModified()) {
7642     /* FIX: Avoid the copy here somehow by fixing the traversal */
7643     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7644 
7645     depthVisitor.clear();
7646     newSieve->support(modifiedPoints, depthVisitor);
7647   } /* while */
7648   /* Stratify refined mesh */
7649   /* Calculate new point SF */
7650   _calcNewOverlap(newMesh, mesh, refiner);
7651   /* Calculate new labels */
7652   _createLabels(newMesh, mesh, refiner);
7653 #endif
7654   PetscFunctionReturn(0);
7655 }
7656 
7657 #undef __FUNCT__
7658 #define __FUNCT__ "DMPlexSetRefinementUniform"
7659 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7660 {
7661   DM_Plex *mesh = (DM_Plex *) dm->data;
7662 
7663   PetscFunctionBegin;
7664   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7665   mesh->refinementUniform = refinementUniform;
7666   PetscFunctionReturn(0);
7667 }
7668 
7669 #undef __FUNCT__
7670 #define __FUNCT__ "DMPlexGetRefinementUniform"
7671 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7672 {
7673   DM_Plex *mesh = (DM_Plex *) dm->data;
7674 
7675   PetscFunctionBegin;
7676   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7677   PetscValidPointer(refinementUniform,  2);
7678   *refinementUniform = mesh->refinementUniform;
7679   PetscFunctionReturn(0);
7680 }
7681 
7682 #undef __FUNCT__
7683 #define __FUNCT__ "DMPlexSetRefinementLimit"
7684 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7685 {
7686   DM_Plex *mesh = (DM_Plex *) dm->data;
7687 
7688   PetscFunctionBegin;
7689   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7690   mesh->refinementLimit = refinementLimit;
7691   PetscFunctionReturn(0);
7692 }
7693 
7694 #undef __FUNCT__
7695 #define __FUNCT__ "DMPlexGetRefinementLimit"
7696 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7697 {
7698   DM_Plex *mesh = (DM_Plex *) dm->data;
7699 
7700   PetscFunctionBegin;
7701   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7702   PetscValidPointer(refinementLimit,  2);
7703   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7704   *refinementLimit = mesh->refinementLimit;
7705   PetscFunctionReturn(0);
7706 }
7707 
7708 #undef __FUNCT__
7709 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7710 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7711 {
7712   PetscInt       dim, cStart, coneSize, cMax;
7713   PetscErrorCode ierr;
7714 
7715   PetscFunctionBegin;
7716   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7717   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7718   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7719   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7720   switch (dim) {
7721   case 2:
7722     switch (coneSize) {
7723     case 3:
7724       if (cMax >= 0) {
7725         *cellRefiner = 3; /* Hybrid */
7726       } else {
7727         *cellRefiner = 1; /* Triangular */
7728       }
7729       break;
7730     case 4:
7731       if (cMax >= 0) {
7732         *cellRefiner = 4; /* Hybrid */
7733       } else {
7734         *cellRefiner = 2; /* Quadrilateral */
7735       }
7736       break;
7737     default:
7738       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7739     }
7740     break;
7741   default:
7742     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7743   }
7744   PetscFunctionReturn(0);
7745 }
7746 
7747 #undef __FUNCT__
7748 #define __FUNCT__ "DMRefine_Plex"
7749 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7750 {
7751   PetscReal      refinementLimit;
7752   PetscInt       dim, cStart, cEnd;
7753   char           genname[1024], *name = PETSC_NULL;
7754   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7755   PetscErrorCode ierr;
7756 
7757   PetscFunctionBegin;
7758   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7759   if (isUniform) {
7760     CellRefiner cellRefiner;
7761 
7762     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7763     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7764     PetscFunctionReturn(0);
7765   }
7766   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7767   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7768   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7769   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7770   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7771   if (flg) {name = genname;}
7772   if (name) {
7773     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7774     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7775     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7776   }
7777   switch (dim) {
7778   case 2:
7779     if (!name || isTriangle) {
7780 #if defined(PETSC_HAVE_TRIANGLE)
7781       double  *maxVolumes;
7782       PetscInt c;
7783 
7784       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7785       for (c = 0; c < cEnd-cStart; ++c) {
7786         maxVolumes[c] = refinementLimit;
7787       }
7788       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7789 #else
7790       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7791 #endif
7792     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7793     break;
7794   case 3:
7795     if (!name || isCTetgen) {
7796 #if defined(PETSC_HAVE_CTETGEN)
7797       PetscReal *maxVolumes;
7798       PetscInt   c;
7799 
7800       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7801       for (c = 0; c < cEnd-cStart; ++c) {
7802         maxVolumes[c] = refinementLimit;
7803       }
7804       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7805 #else
7806       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7807 #endif
7808     } else if (isTetgen) {
7809 #if defined(PETSC_HAVE_TETGEN)
7810       double  *maxVolumes;
7811       PetscInt c;
7812 
7813       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7814       for (c = 0; c < cEnd-cStart; ++c) {
7815         maxVolumes[c] = refinementLimit;
7816       }
7817       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7818 #else
7819       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7820 #endif
7821     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7822     break;
7823   default:
7824     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7825   }
7826   PetscFunctionReturn(0);
7827 }
7828 
7829 #undef __FUNCT__
7830 #define __FUNCT__ "DMPlexGetDepth"
7831 /*@
7832   DMPlexGetDepth - get the number of strata
7833 
7834   Not Collective
7835 
7836   Input Parameters:
7837 . dm           - The DMPlex object
7838 
7839   Output Parameters:
7840 . depth - number of strata
7841 
7842   Level: developer
7843 
7844   Notes:
7845   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7846 
7847 .keywords: mesh, points
7848 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7849 @*/
7850 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7851 {
7852   PetscInt       d;
7853   PetscErrorCode ierr;
7854 
7855   PetscFunctionBegin;
7856   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7857   PetscValidPointer(depth, 2);
7858   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7859   *depth = d-1;
7860   PetscFunctionReturn(0);
7861 }
7862 
7863 #undef __FUNCT__
7864 #define __FUNCT__ "DMPlexGetDepthStratum"
7865 /*@
7866   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7867 
7868   Not Collective
7869 
7870   Input Parameters:
7871 + dm           - The DMPlex object
7872 - stratumValue - The requested depth
7873 
7874   Output Parameters:
7875 + start - The first point at this depth
7876 - end   - One beyond the last point at this depth
7877 
7878   Level: developer
7879 
7880 .keywords: mesh, points
7881 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7882 @*/
7883 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7884 {
7885   DM_Plex    *mesh = (DM_Plex *) dm->data;
7886   DMLabel        next = mesh->labels;
7887   PetscBool      flg  = PETSC_FALSE;
7888   PetscInt       depth;
7889   PetscErrorCode ierr;
7890 
7891   PetscFunctionBegin;
7892   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7893   if (stratumValue < 0) {
7894     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7895     PetscFunctionReturn(0);
7896   } else {
7897     PetscInt pStart, pEnd;
7898 
7899     if (start) {*start = 0;}
7900     if (end)   {*end   = 0;}
7901     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7902     if (pStart == pEnd) {PetscFunctionReturn(0);}
7903   }
7904   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7905   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7906   /* We should have a generic GetLabel() and a Label class */
7907   while (next) {
7908     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7909     if (flg) break;
7910     next = next->next;
7911   }
7912   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7913   depth = stratumValue;
7914   if ((depth < 0) || (depth >= next->numStrata)) {
7915     if (start) {*start = 0;}
7916     if (end)   {*end   = 0;}
7917   } else {
7918     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7919     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7920   }
7921   PetscFunctionReturn(0);
7922 }
7923 
7924 #undef __FUNCT__
7925 #define __FUNCT__ "DMPlexGetHeightStratum"
7926 /*@
7927   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7928 
7929   Not Collective
7930 
7931   Input Parameters:
7932 + dm           - The DMPlex object
7933 - stratumValue - The requested height
7934 
7935   Output Parameters:
7936 + start - The first point at this height
7937 - end   - One beyond the last point at this height
7938 
7939   Level: developer
7940 
7941 .keywords: mesh, points
7942 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7943 @*/
7944 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7945 {
7946   DM_Plex        *mesh = (DM_Plex *) dm->data;
7947   DMLabel        next = mesh->labels;
7948   PetscBool      flg  = PETSC_FALSE;
7949   PetscInt       depth;
7950   PetscErrorCode ierr;
7951 
7952   PetscFunctionBegin;
7953   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7954   if (stratumValue < 0) {
7955     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7956   } else {
7957     PetscInt pStart, pEnd;
7958 
7959     if (start) {*start = 0;}
7960     if (end)   {*end   = 0;}
7961     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7962     if (pStart == pEnd) {PetscFunctionReturn(0);}
7963   }
7964   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7965   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7966   /* We should have a generic GetLabel() and a Label class */
7967   while (next) {
7968     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7969     if (flg) break;
7970     next = next->next;
7971   }
7972   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7973   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7974   if ((depth < 0) || (depth >= next->numStrata)) {
7975     if (start) {*start = 0;}
7976     if (end)   {*end   = 0;}
7977   } else {
7978     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7979     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7980   }
7981   PetscFunctionReturn(0);
7982 }
7983 
7984 #undef __FUNCT__
7985 #define __FUNCT__ "DMPlexCreateSectionInitial"
7986 /* Set the number of dof on each point and separate by fields */
7987 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7988 {
7989   PetscInt      *numDofTot;
7990   PetscInt       pStart = 0, pEnd = 0;
7991   PetscInt       p, d, f;
7992   PetscErrorCode ierr;
7993 
7994   PetscFunctionBegin;
7995   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7996   for (d = 0; d <= dim; ++d) {
7997     numDofTot[d] = 0;
7998     for (f = 0; f < numFields; ++f) {
7999       numDofTot[d] += numDof[f*(dim+1)+d];
8000     }
8001   }
8002   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
8003   if (numFields > 0) {
8004     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
8005     if (numComp) {
8006       for (f = 0; f < numFields; ++f) {
8007         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
8008       }
8009     }
8010   }
8011   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8012   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
8013   for (d = 0; d <= dim; ++d) {
8014     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
8015     for (p = pStart; p < pEnd; ++p) {
8016       for (f = 0; f < numFields; ++f) {
8017         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
8018       }
8019       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
8020     }
8021   }
8022   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
8023   PetscFunctionReturn(0);
8024 }
8025 
8026 #undef __FUNCT__
8027 #define __FUNCT__ "DMPlexCreateSectionBCDof"
8028 /* Set the number of dof on each point and separate by fields
8029    If constDof is PETSC_DETERMINE, constrain every dof on the point
8030 */
8031 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
8032 {
8033   PetscInt       numFields;
8034   PetscInt       bc;
8035   PetscErrorCode ierr;
8036 
8037   PetscFunctionBegin;
8038   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8039   for (bc = 0; bc < numBC; ++bc) {
8040     PetscInt        field = 0;
8041     const PetscInt *idx;
8042     PetscInt        n, i;
8043 
8044     if (numFields) {field = bcField[bc];}
8045     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
8046     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8047     for (i = 0; i < n; ++i) {
8048       const PetscInt p = idx[i];
8049       PetscInt       numConst = constDof;
8050 
8051       /* Constrain every dof on the point */
8052       if (numConst < 0) {
8053         if (numFields) {
8054           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
8055         } else {
8056           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
8057         }
8058       }
8059       if (numFields) {
8060         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
8061       }
8062       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
8063     }
8064     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8065   }
8066   PetscFunctionReturn(0);
8067 }
8068 
8069 #undef __FUNCT__
8070 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
8071 /* Set the constrained indices on each point and separate by fields */
8072 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
8073 {
8074   PetscInt      *maxConstraints;
8075   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
8076   PetscErrorCode ierr;
8077 
8078   PetscFunctionBegin;
8079   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8080   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8081   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
8082   for (f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
8083   for (p = pStart; p < pEnd; ++p) {
8084     PetscInt cdof;
8085 
8086     if (numFields) {
8087       for (f = 0; f < numFields; ++f) {
8088         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
8089         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
8090       }
8091     } else {
8092       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8093       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
8094     }
8095   }
8096   for (f = 0; f < numFields; ++f) {
8097     maxConstraints[numFields] += maxConstraints[f];
8098   }
8099   if (maxConstraints[numFields]) {
8100     PetscInt *indices;
8101 
8102     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8103     for (p = pStart; p < pEnd; ++p) {
8104       PetscInt cdof, d;
8105 
8106       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8107       if (cdof) {
8108         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
8109         if (numFields) {
8110           PetscInt numConst = 0, foff = 0;
8111 
8112           for (f = 0; f < numFields; ++f) {
8113             PetscInt cfdof, fdof;
8114 
8115             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8116             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
8117             /* Change constraint numbering from absolute local dof number to field relative local dof number */
8118             for (d = 0; d < cfdof; ++d) {
8119               indices[numConst+d] = d;
8120             }
8121             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
8122             for (d = 0; d < cfdof; ++d) {
8123               indices[numConst+d] += foff;
8124             }
8125             numConst += cfdof;
8126             foff     += fdof;
8127           }
8128           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8129         } else {
8130           for (d = 0; d < cdof; ++d) {
8131             indices[d] = d;
8132           }
8133         }
8134         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8135       }
8136     }
8137     ierr = PetscFree(indices);CHKERRQ(ierr);
8138   }
8139   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
8140   PetscFunctionReturn(0);
8141 }
8142 
8143 #undef __FUNCT__
8144 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
8145 /* Set the constrained field indices on each point */
8146 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
8147 {
8148   const PetscInt *points, *indices;
8149   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
8150   PetscErrorCode  ierr;
8151 
8152   PetscFunctionBegin;
8153   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8154   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8155 
8156   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8157   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8158   if (!constraintIndices) {
8159     PetscInt *idx, i;
8160 
8161     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8162     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8163     for (i = 0; i < maxDof; ++i) {idx[i] = i;}
8164     for (p = 0; p < numPoints; ++p) {
8165       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8166     }
8167     ierr = PetscFree(idx);CHKERRQ(ierr);
8168   } else {
8169     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8170     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8171     for (p = 0; p < numPoints; ++p) {
8172       PetscInt fcdof;
8173 
8174       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8175       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);
8176       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8177     }
8178     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8179   }
8180   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8181   PetscFunctionReturn(0);
8182 }
8183 
8184 #undef __FUNCT__
8185 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8186 /* Set the constrained indices on each point and separate by fields */
8187 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8188 {
8189   PetscInt      *indices;
8190   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8191   PetscErrorCode ierr;
8192 
8193   PetscFunctionBegin;
8194   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8195   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8196   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8197   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8198   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8199   for (p = pStart; p < pEnd; ++p) {
8200     PetscInt cdof, d;
8201 
8202     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8203     if (cdof) {
8204       PetscInt numConst = 0, foff = 0;
8205 
8206       for (f = 0; f < numFields; ++f) {
8207         const PetscInt *fcind;
8208         PetscInt        fdof, fcdof;
8209 
8210         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8211         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8212         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8213         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8214         for (d = 0; d < fcdof; ++d) {
8215           indices[numConst+d] = fcind[d]+foff;
8216         }
8217         foff     += fdof;
8218         numConst += fcdof;
8219       }
8220       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8221       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8222     }
8223   }
8224   ierr = PetscFree(indices);CHKERRQ(ierr);
8225   PetscFunctionReturn(0);
8226 }
8227 
8228 #undef __FUNCT__
8229 #define __FUNCT__ "DMPlexCreateSection"
8230 /*@C
8231   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8232 
8233   Not Collective
8234 
8235   Input Parameters:
8236 + dm        - The DMPlex object
8237 . dim       - The spatial dimension of the problem
8238 . numFields - The number of fields in the problem
8239 . numComp   - An array of size numFields that holds the number of components for each field
8240 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8241 . numBC     - The number of boundary conditions
8242 . bcField   - An array of size numBC giving the field number for each boundry condition
8243 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8244 
8245   Output Parameter:
8246 . section - The PetscSection object
8247 
8248   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
8249   nubmer of dof for field 0 on each edge.
8250 
8251   Level: developer
8252 
8253 .keywords: mesh, elements
8254 .seealso: DMPlexCreate(), PetscSectionCreate()
8255 @*/
8256 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8257 {
8258   PetscErrorCode ierr;
8259 
8260   PetscFunctionBegin;
8261   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8262   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8263   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8264   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8265   {
8266     PetscBool view = PETSC_FALSE;
8267 
8268     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8269     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8270   }
8271   PetscFunctionReturn(0);
8272 }
8273 
8274 #undef __FUNCT__
8275 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8276 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8277 {
8278   PetscSection   section;
8279   PetscErrorCode ierr;
8280 
8281   PetscFunctionBegin;
8282   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8283   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8284   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8285   PetscFunctionReturn(0);
8286 }
8287 
8288 #undef __FUNCT__
8289 #define __FUNCT__ "DMPlexGetCoordinateSection"
8290 /*@
8291   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8292 
8293   Not Collective
8294 
8295   Input Parameter:
8296 . dm - The DMPlex object
8297 
8298   Output Parameter:
8299 . section - The PetscSection object
8300 
8301   Level: intermediate
8302 
8303 .keywords: mesh, coordinates
8304 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8305 @*/
8306 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8307 {
8308   DM             cdm;
8309   PetscErrorCode ierr;
8310 
8311   PetscFunctionBegin;
8312   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8313   PetscValidPointer(section, 2);
8314   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8315   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8316   PetscFunctionReturn(0);
8317 }
8318 
8319 #undef __FUNCT__
8320 #define __FUNCT__ "DMPlexSetCoordinateSection"
8321 /*@
8322   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8323 
8324   Not Collective
8325 
8326   Input Parameters:
8327 + dm      - The DMPlex object
8328 - section - The PetscSection object
8329 
8330   Level: intermediate
8331 
8332 .keywords: mesh, coordinates
8333 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8334 @*/
8335 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8336 {
8337   DM             cdm;
8338   PetscErrorCode ierr;
8339 
8340   PetscFunctionBegin;
8341   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8342   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8343   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8344   PetscFunctionReturn(0);
8345 }
8346 
8347 #undef __FUNCT__
8348 #define __FUNCT__ "DMPlexGetConeSection"
8349 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8350 {
8351   DM_Plex *mesh = (DM_Plex *) dm->data;
8352 
8353   PetscFunctionBegin;
8354   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8355   if (section) *section = mesh->coneSection;
8356   PetscFunctionReturn(0);
8357 }
8358 
8359 #undef __FUNCT__
8360 #define __FUNCT__ "DMPlexGetCones"
8361 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8362 {
8363   DM_Plex *mesh = (DM_Plex *) dm->data;
8364 
8365   PetscFunctionBegin;
8366   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8367   if (cones) *cones = mesh->cones;
8368   PetscFunctionReturn(0);
8369 }
8370 
8371 #undef __FUNCT__
8372 #define __FUNCT__ "DMPlexGetConeOrientations"
8373 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8374 {
8375   DM_Plex *mesh = (DM_Plex *) dm->data;
8376 
8377   PetscFunctionBegin;
8378   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8379   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8380   PetscFunctionReturn(0);
8381 }
8382 
8383 #undef __FUNCT__
8384 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8385 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8386 {
8387   const PetscInt embedDim = 2;
8388   PetscReal      x = PetscRealPart(point[0]);
8389   PetscReal      y = PetscRealPart(point[1]);
8390   PetscReal      v0[2], J[4], invJ[4], detJ;
8391   PetscReal      xi, eta;
8392   PetscErrorCode ierr;
8393 
8394   PetscFunctionBegin;
8395   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8396   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8397   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8398 
8399   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
8400     *cell = c;
8401   } else {
8402     *cell = -1;
8403   }
8404   PetscFunctionReturn(0);
8405 }
8406 
8407 #undef __FUNCT__
8408 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8409 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8410 {
8411   PetscSection       coordSection;
8412   Vec                coordsLocal;
8413   const PetscScalar *coords;
8414   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8415   PetscReal          x         = PetscRealPart(point[0]);
8416   PetscReal          y         = PetscRealPart(point[1]);
8417   PetscInt           crossings = 0, f;
8418   PetscErrorCode     ierr;
8419 
8420   PetscFunctionBegin;
8421   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8422   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8423   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8424   for (f = 0; f < 4; ++f) {
8425     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8426     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8427     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8428     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8429     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8430     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8431     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8432     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8433     if ((cond1 || cond2)  && above) ++crossings;
8434   }
8435   if (crossings % 2) {
8436     *cell = c;
8437   } else {
8438     *cell = -1;
8439   }
8440   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8441   PetscFunctionReturn(0);
8442 }
8443 
8444 #undef __FUNCT__
8445 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8446 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8447 {
8448   const PetscInt embedDim = 3;
8449   PetscReal      v0[3], J[9], invJ[9], detJ;
8450   PetscReal      x = PetscRealPart(point[0]);
8451   PetscReal      y = PetscRealPart(point[1]);
8452   PetscReal      z = PetscRealPart(point[2]);
8453   PetscReal      xi, eta, zeta;
8454   PetscErrorCode ierr;
8455 
8456   PetscFunctionBegin;
8457   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8458   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8459   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8460   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8461 
8462   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
8463     *cell = c;
8464   } else {
8465     *cell = -1;
8466   }
8467   PetscFunctionReturn(0);
8468 }
8469 
8470 #undef __FUNCT__
8471 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8472 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8473 {
8474   PetscSection       coordSection;
8475   Vec                coordsLocal;
8476   const PetscScalar *coords;
8477   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8478                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8479   PetscBool          found     = PETSC_TRUE;
8480   PetscInt           f;
8481   PetscErrorCode     ierr;
8482 
8483   PetscFunctionBegin;
8484   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8485   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8486   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8487   for (f = 0; f < 6; ++f) {
8488     /* Check the point is under plane */
8489     /*   Get face normal */
8490     PetscReal v_i[3];
8491     PetscReal v_j[3];
8492     PetscReal normal[3];
8493     PetscReal pp[3];
8494     PetscReal dot;
8495 
8496     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8497     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8498     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8499     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8500     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8501     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8502     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8503     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8504     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8505     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8506     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8507     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8508     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8509 
8510     /* Check that projected point is in face (2D location problem) */
8511     if (dot < 0.0) {
8512       found = PETSC_FALSE;
8513       break;
8514     }
8515   }
8516   if (found) {
8517     *cell = c;
8518   } else {
8519     *cell = -1;
8520   }
8521   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8522   PetscFunctionReturn(0);
8523 }
8524 
8525 #undef __FUNCT__
8526 #define __FUNCT__ "DMLocatePoints_Plex"
8527 /*
8528  Need to implement using the guess
8529 */
8530 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8531 {
8532   PetscInt       cell = -1/*, guess = -1*/;
8533   PetscInt       bs, numPoints, p;
8534   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8535   PetscInt      *cells;
8536   PetscScalar   *a;
8537   PetscErrorCode ierr;
8538 
8539   PetscFunctionBegin;
8540   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8541   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8542   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8543   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8544   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8545   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8546   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8547   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);
8548   numPoints /= bs;
8549   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8550   for (p = 0; p < numPoints; ++p) {
8551     const PetscScalar *point = &a[p*bs];
8552 
8553     switch (dim) {
8554     case 2:
8555       for (c = cStart; c < cEnd; ++c) {
8556         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8557         switch (coneSize) {
8558         case 3:
8559           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8560           break;
8561         case 4:
8562           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8563           break;
8564         default:
8565           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8566         }
8567         if (cell >= 0) break;
8568       }
8569       break;
8570     case 3:
8571       for (c = cStart; c < cEnd; ++c) {
8572         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8573         switch (coneSize) {
8574         case 4:
8575           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8576           break;
8577         case 8:
8578           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8579           break;
8580         default:
8581           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8582         }
8583         if (cell >= 0) break;
8584       }
8585       break;
8586     default:
8587       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8588     }
8589     cells[p] = cell;
8590   }
8591   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8592   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8593   PetscFunctionReturn(0);
8594 }
8595 
8596 /******************************** FEM Support **********************************/
8597 
8598 #undef __FUNCT__
8599 #define __FUNCT__ "DMPlexVecGetClosure"
8600 /*@C
8601   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8602 
8603   Not collective
8604 
8605   Input Parameters:
8606 + dm - The DM
8607 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8608 . v - The local vector
8609 - point - The sieve point in the DM
8610 
8611   Output Parameters:
8612 + csize - The number of values in the closure, or PETSC_NULL
8613 - values - The array of values, which is a borrowed array and should not be freed
8614 
8615   Level: intermediate
8616 
8617 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8618 @*/
8619 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8620 {
8621   PetscScalar    *array, *vArray;
8622   PetscInt       *points = PETSC_NULL;
8623   PetscInt        offsets[32];
8624   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8625   PetscErrorCode  ierr;
8626 
8627   PetscFunctionBegin;
8628   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8629   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8630   if (!section) {
8631     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8632   }
8633   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8634   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8635   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8636   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8637   /* Compress out points not in the section */
8638   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8639   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8640     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8641       points[q*2]   = points[p];
8642       points[q*2+1] = points[p+1];
8643       ++q;
8644     }
8645   }
8646   numPoints = q;
8647   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8648     PetscInt dof, fdof;
8649 
8650     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8651     for (f = 0; f < numFields; ++f) {
8652       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8653       offsets[f+1] += fdof;
8654     }
8655     size += dof;
8656   }
8657   for (f = 1; f < numFields; ++f) {
8658     offsets[f+1] += offsets[f];
8659   }
8660   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8661   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8662   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8663   for (p = 0; p < numPoints*2; p += 2) {
8664     PetscInt     o = points[p+1];
8665     PetscInt     dof, off, d;
8666     PetscScalar *varr;
8667 
8668     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8669     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8670     varr = &vArray[off];
8671     if (numFields) {
8672       PetscInt fdof, foff, fcomp, f, c;
8673 
8674       for (f = 0, foff = 0; f < numFields; ++f) {
8675         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8676         if (o >= 0) {
8677           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8678             array[offsets[f]] = varr[foff+d];
8679           }
8680         } else {
8681           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8682           for (d = fdof/fcomp-1; d >= 0; --d) {
8683             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8684               array[offsets[f]] = varr[foff+d*fcomp+c];
8685             }
8686           }
8687         }
8688         foff += fdof;
8689       }
8690     } else {
8691       if (o >= 0) {
8692         for (d = 0; d < dof; ++d, ++offsets[0]) {
8693           array[offsets[0]] = varr[d];
8694         }
8695       } else {
8696         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8697           array[offsets[0]] = varr[d];
8698         }
8699       }
8700     }
8701   }
8702   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8703   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8704   if (csize) *csize = size;
8705   *values = array;
8706   PetscFunctionReturn(0);
8707 }
8708 
8709 #undef __FUNCT__
8710 #define __FUNCT__ "DMPlexVecRestoreClosure"
8711 /*@C
8712   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8713 
8714   Not collective
8715 
8716   Input Parameters:
8717 + dm - The DM
8718 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8719 . v - The local vector
8720 . point - The sieve point in the DM
8721 . csize - The number of values in the closure, or PETSC_NULL
8722 - values - The array of values, which is a borrowed array and should not be freed
8723 
8724   Level: intermediate
8725 
8726 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8727 @*/
8728 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8729 {
8730   PetscInt        size = 0;
8731   PetscErrorCode  ierr;
8732 
8733   PetscFunctionBegin;
8734   /* Should work without recalculating size */
8735   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8736   PetscFunctionReturn(0);
8737 }
8738 
8739 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8740 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8741 
8742 #undef __FUNCT__
8743 #define __FUNCT__ "updatePoint_private"
8744 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8745 {
8746   PetscInt        cdof;  /* The number of constraints on this point */
8747   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8748   PetscScalar    *a;
8749   PetscInt        off, cind = 0, k;
8750   PetscErrorCode  ierr;
8751 
8752   PetscFunctionBegin;
8753   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8754   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8755   a    = &array[off];
8756   if (!cdof || setBC) {
8757     if (orientation >= 0) {
8758       for (k = 0; k < dof; ++k) {
8759         fuse(&a[k], values[k]);
8760       }
8761     } else {
8762       for (k = 0; k < dof; ++k) {
8763         fuse(&a[k], values[dof-k-1]);
8764       }
8765     }
8766   } else {
8767     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8768     if (orientation >= 0) {
8769       for (k = 0; k < dof; ++k) {
8770         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8771         fuse(&a[k], values[k]);
8772       }
8773     } else {
8774       for (k = 0; k < dof; ++k) {
8775         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8776         fuse(&a[k], values[dof-k-1]);
8777       }
8778     }
8779   }
8780   PetscFunctionReturn(0);
8781 }
8782 
8783 #undef __FUNCT__
8784 #define __FUNCT__ "updatePointFields_private"
8785 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8786 {
8787   PetscScalar   *a;
8788   PetscInt       numFields, off, foff, f;
8789   PetscErrorCode ierr;
8790 
8791   PetscFunctionBegin;
8792   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8793   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8794   a    = &array[off];
8795   for (f = 0, foff = 0; f < numFields; ++f) {
8796     PetscInt        fdof, fcomp, fcdof;
8797     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8798     PetscInt        cind = 0, k, c;
8799 
8800     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8801     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8802     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8803     if (!fcdof || setBC) {
8804       if (orientation >= 0) {
8805         for (k = 0; k < fdof; ++k) {
8806           fuse(&a[foff+k], values[foffs[f]+k]);
8807         }
8808       } else {
8809         for (k = fdof/fcomp-1; k >= 0; --k) {
8810           for (c = 0; c < fcomp; ++c) {
8811             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8812           }
8813         }
8814       }
8815     } else {
8816       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8817       if (orientation >= 0) {
8818         for (k = 0; k < fdof; ++k) {
8819           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8820           fuse(&a[foff+k], values[foffs[f]+k]);
8821         }
8822       } else {
8823         for (k = fdof/fcomp-1; k >= 0; --k) {
8824           for (c = 0; c < fcomp; ++c) {
8825             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8826             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8827           }
8828         }
8829       }
8830     }
8831     foff     += fdof;
8832     foffs[f] += fdof;
8833   }
8834   PetscFunctionReturn(0);
8835 }
8836 
8837 #undef __FUNCT__
8838 #define __FUNCT__ "DMPlexVecSetClosure"
8839 /*@C
8840   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8841 
8842   Not collective
8843 
8844   Input Parameters:
8845 + dm - The DM
8846 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8847 . v - The local vector
8848 . point - The sieve point in the DM
8849 . values - The array of values, which is a borrowed array and should not be freed
8850 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8851 
8852   Level: intermediate
8853 
8854 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8855 @*/
8856 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8857 {
8858   PetscScalar    *array;
8859   PetscInt       *points = PETSC_NULL;
8860   PetscInt        offsets[32];
8861   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8862   PetscErrorCode  ierr;
8863 
8864   PetscFunctionBegin;
8865   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8866   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8867   if (!section) {
8868     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8869   }
8870   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8871   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8872   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8873   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8874   /* Compress out points not in the section */
8875   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8876   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8877     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8878       points[q*2]   = points[p];
8879       points[q*2+1] = points[p+1];
8880       ++q;
8881     }
8882   }
8883   numPoints = q;
8884   for (p = 0; p < numPoints*2; p += 2) {
8885     PetscInt fdof;
8886 
8887     for (f = 0; f < numFields; ++f) {
8888       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8889       offsets[f+1] += fdof;
8890     }
8891   }
8892   for (f = 1; f < numFields; ++f) {
8893     offsets[f+1] += offsets[f];
8894   }
8895   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8896   if (numFields) {
8897     switch (mode) {
8898     case INSERT_VALUES:
8899       for (p = 0; p < numPoints*2; p += 2) {
8900         PetscInt o = points[p+1];
8901         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8902       } break;
8903     case INSERT_ALL_VALUES:
8904       for (p = 0; p < numPoints*2; p += 2) {
8905         PetscInt o = points[p+1];
8906         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8907       } break;
8908     case ADD_VALUES:
8909       for (p = 0; p < numPoints*2; p += 2) {
8910         PetscInt o = points[p+1];
8911         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8912       } break;
8913     case ADD_ALL_VALUES:
8914       for (p = 0; p < numPoints*2; p += 2) {
8915         PetscInt o = points[p+1];
8916         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8917       } break;
8918     default:
8919       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8920     }
8921   } else {
8922     switch (mode) {
8923     case INSERT_VALUES:
8924       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8925         PetscInt o = points[p+1];
8926         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8927         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8928       } break;
8929     case INSERT_ALL_VALUES:
8930       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8931         PetscInt o = points[p+1];
8932         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8933         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8934       } break;
8935     case ADD_VALUES:
8936       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8937         PetscInt o = points[p+1];
8938         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8939         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8940       } break;
8941     case ADD_ALL_VALUES:
8942       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8943         PetscInt o = points[p+1];
8944         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8945         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8946       } break;
8947     default:
8948       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8949     }
8950   }
8951   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8952   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8953   PetscFunctionReturn(0);
8954 }
8955 
8956 #undef __FUNCT__
8957 #define __FUNCT__ "DMPlexPrintMatSetValues"
8958 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8959 {
8960   PetscMPIInt    rank;
8961   PetscInt       i, j;
8962   PetscErrorCode ierr;
8963 
8964   PetscFunctionBegin;
8965   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8966   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8967   for (i = 0; i < numIndices; i++) {
8968     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8969   }
8970   for (i = 0; i < numIndices; i++) {
8971     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8972     for (j = 0; j < numIndices; j++) {
8973 #if defined(PETSC_USE_COMPLEX)
8974       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8975 #else
8976       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8977 #endif
8978     }
8979     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8980   }
8981   PetscFunctionReturn(0);
8982 }
8983 
8984 #undef __FUNCT__
8985 #define __FUNCT__ "indicesPoint_private"
8986 /* . off - The global offset of this point */
8987 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8988 {
8989   PetscInt        cdof;  /* The number of constraints on this point */
8990   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8991   PetscInt        cind = 0, k;
8992   PetscErrorCode  ierr;
8993 
8994   PetscFunctionBegin;
8995   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8996   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8997   if (!cdof || setBC) {
8998     if (orientation >= 0) {
8999       for (k = 0; k < dof; ++k) {
9000         indices[k] = off+k;
9001       }
9002     } else {
9003       for (k = 0; k < dof; ++k) {
9004         indices[dof-k-1] = off+k;
9005       }
9006     }
9007   } else {
9008     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
9009     if (orientation >= 0) {
9010       for (k = 0; k < dof; ++k) {
9011         if ((cind < cdof) && (k == cdofs[cind])) {
9012           /* Insert check for returning constrained indices */
9013           indices[k] = -(off+k+1);
9014           ++cind;
9015         } else {
9016           indices[k] = off+k-cind;
9017         }
9018       }
9019     } else {
9020       for (k = 0; k < dof; ++k) {
9021         if ((cind < cdof) && (k == cdofs[cind])) {
9022           /* Insert check for returning constrained indices */
9023           indices[dof-k-1] = -(off+k+1);
9024           ++cind;
9025         } else {
9026           indices[dof-k-1] = off+k-cind;
9027         }
9028       }
9029     }
9030   }
9031   PetscFunctionReturn(0);
9032 }
9033 
9034 #undef __FUNCT__
9035 #define __FUNCT__ "indicesPointFields_private"
9036 /* . off - The global offset of this point */
9037 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
9038 {
9039   PetscInt       numFields, foff, f;
9040   PetscErrorCode ierr;
9041 
9042   PetscFunctionBegin;
9043   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9044   for (f = 0, foff = 0; f < numFields; ++f) {
9045     PetscInt        fdof, fcomp, cfdof;
9046     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
9047     PetscInt        cind = 0, k, c;
9048 
9049     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
9050     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
9051     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
9052     if (!cfdof || setBC) {
9053       if (orientation >= 0) {
9054         for (k = 0; k < fdof; ++k) {
9055           indices[foffs[f]+k] = off+foff+k;
9056         }
9057       } else {
9058         for (k = fdof/fcomp-1; k >= 0; --k) {
9059           for (c = 0; c < fcomp; ++c) {
9060             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
9061           }
9062         }
9063       }
9064     } else {
9065       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
9066       if (orientation >= 0) {
9067         for (k = 0; k < fdof; ++k) {
9068           if ((cind < cfdof) && (k == fcdofs[cind])) {
9069             indices[foffs[f]+k] = -(off+foff+k+1);
9070             ++cind;
9071           } else {
9072             indices[foffs[f]+k] = off+foff+k-cind;
9073           }
9074         }
9075       } else {
9076         for (k = fdof/fcomp-1; k >= 0; --k) {
9077           for (c = 0; c < fcomp; ++c) {
9078             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
9079               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
9080               ++cind;
9081             } else {
9082               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
9083             }
9084           }
9085         }
9086       }
9087     }
9088     foff     += fdof - cfdof;
9089     foffs[f] += fdof;
9090   }
9091   PetscFunctionReturn(0);
9092 }
9093 
9094 #undef __FUNCT__
9095 #define __FUNCT__ "DMPlexMatSetClosure"
9096 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
9097 {
9098   DM_Plex     *mesh   = (DM_Plex *) dm->data;
9099   PetscInt       *points = PETSC_NULL;
9100   PetscInt       *indices;
9101   PetscInt        offsets[32];
9102   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
9103   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
9104   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
9105   PetscErrorCode  ierr;
9106 
9107   PetscFunctionBegin;
9108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9109   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
9110   if (useDefault) {
9111     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9112   }
9113   if (useGlobalDefault) {
9114     if (useDefault) {
9115       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
9116     } else {
9117       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9118     }
9119   }
9120   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9121   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
9122   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
9123   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9124   /* Compress out points not in the section */
9125   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
9126   for (p = 0, q = 0; p < numPoints*2; p += 2) {
9127     if ((points[p] >= pStart) && (points[p] < pEnd)) {
9128       points[q*2]   = points[p];
9129       points[q*2+1] = points[p+1];
9130       ++q;
9131     }
9132   }
9133   numPoints = q;
9134   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
9135     PetscInt fdof;
9136 
9137     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
9138     for (f = 0; f < numFields; ++f) {
9139       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
9140       offsets[f+1] += fdof;
9141     }
9142     numIndices += dof;
9143   }
9144   for (f = 1; f < numFields; ++f) {
9145     offsets[f+1] += offsets[f];
9146   }
9147   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
9148   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9149   if (numFields) {
9150     for (p = 0; p < numPoints*2; p += 2) {
9151       PetscInt o = points[p+1];
9152       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9153       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
9154     }
9155   } else {
9156     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
9157       PetscInt o = points[p+1];
9158       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9159       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
9160     }
9161   }
9162   if (useGlobalDefault && !useDefault) {
9163     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9164   }
9165   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
9166   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9167   if (ierr) {
9168     PetscMPIInt    rank;
9169     PetscErrorCode ierr2;
9170 
9171     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
9172     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9173     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9174     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9175     CHKERRQ(ierr);
9176   }
9177   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9178   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9179   PetscFunctionReturn(0);
9180 }
9181 
9182 #undef __FUNCT__
9183 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9184 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9185 {
9186   PetscSection       coordSection;
9187   Vec                coordinates;
9188   const PetscScalar *coords;
9189   const PetscInt     dim = 2;
9190   PetscInt           d, f;
9191   PetscErrorCode     ierr;
9192 
9193   PetscFunctionBegin;
9194   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9195   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9196   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9197   if (v0) {
9198     for (d = 0; d < dim; d++) {
9199       v0[d] = PetscRealPart(coords[d]);
9200     }
9201   }
9202   if (J) {
9203     for (d = 0; d < dim; d++) {
9204       for (f = 0; f < dim; f++) {
9205         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9206       }
9207     }
9208     *detJ = J[0]*J[3] - J[1]*J[2];
9209 #if 0
9210     if (detJ < 0.0) {
9211       const PetscReal xLength = mesh->periodicity[0];
9212 
9213       if (xLength != 0.0) {
9214         PetscReal v0x = coords[0*dim+0];
9215 
9216         if (v0x == 0.0) {
9217           v0x = v0[0] = xLength;
9218         }
9219         for (f = 0; f < dim; f++) {
9220           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9221 
9222           J[0*dim+f] = 0.5*(px - v0x);
9223         }
9224       }
9225       detJ = J[0]*J[3] - J[1]*J[2];
9226     }
9227 #endif
9228     PetscLogFlops(8.0 + 3.0);
9229   }
9230   if (invJ) {
9231     const PetscReal invDet = 1.0/(*detJ);
9232 
9233     invJ[0] =  invDet*J[3];
9234     invJ[1] = -invDet*J[1];
9235     invJ[2] = -invDet*J[2];
9236     invJ[3] =  invDet*J[0];
9237     PetscLogFlops(5.0);
9238   }
9239   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9240   PetscFunctionReturn(0);
9241 }
9242 
9243 #undef __FUNCT__
9244 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9245 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9246 {
9247   PetscSection       coordSection;
9248   Vec                coordinates;
9249   const PetscScalar *coords;
9250   const PetscInt     dim = 2;
9251   PetscInt           d, f;
9252   PetscErrorCode     ierr;
9253 
9254   PetscFunctionBegin;
9255   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9256   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9257   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9258   if (v0) {
9259     for (d = 0; d < dim; d++) {
9260       v0[d] = PetscRealPart(coords[d]);
9261     }
9262   }
9263   if (J) {
9264     for (d = 0; d < dim; d++) {
9265       for (f = 0; f < dim; f++) {
9266         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9267       }
9268     }
9269     *detJ = J[0]*J[3] - J[1]*J[2];
9270     PetscLogFlops(8.0 + 3.0);
9271   }
9272   if (invJ) {
9273     const PetscReal invDet = 1.0/(*detJ);
9274 
9275     invJ[0] =  invDet*J[3];
9276     invJ[1] = -invDet*J[1];
9277     invJ[2] = -invDet*J[2];
9278     invJ[3] =  invDet*J[0];
9279     PetscLogFlops(5.0);
9280   }
9281   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9282   PetscFunctionReturn(0);
9283 }
9284 
9285 #undef __FUNCT__
9286 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9287 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9288 {
9289   PetscSection       coordSection;
9290   Vec                coordinates;
9291   const PetscScalar *coords;
9292   const PetscInt     dim = 3;
9293   PetscInt           d, f;
9294   PetscErrorCode     ierr;
9295 
9296   PetscFunctionBegin;
9297   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9298   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9299   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9300   if (v0) {
9301     for (d = 0; d < dim; d++) {
9302       v0[d] = PetscRealPart(coords[d]);
9303     }
9304   }
9305   if (J) {
9306     for (d = 0; d < dim; d++) {
9307       for (f = 0; f < dim; f++) {
9308         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9309       }
9310     }
9311     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9312     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9313              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9314              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9315     PetscLogFlops(18.0 + 12.0);
9316   }
9317   if (invJ) {
9318     const PetscReal invDet = 1.0/(*detJ);
9319 
9320     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9321     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9322     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9323     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9324     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9325     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9326     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9327     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9328     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9329     PetscLogFlops(37.0);
9330   }
9331   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9332   PetscFunctionReturn(0);
9333 }
9334 
9335 #undef __FUNCT__
9336 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9337 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9338 {
9339   PetscSection       coordSection;
9340   Vec                coordinates;
9341   const PetscScalar *coords;
9342   const PetscInt     dim = 3;
9343   PetscInt           d;
9344   PetscErrorCode     ierr;
9345 
9346   PetscFunctionBegin;
9347   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9348   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9349   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9350   if (v0) {
9351     for (d = 0; d < dim; d++) {
9352       v0[d] = PetscRealPart(coords[d]);
9353     }
9354   }
9355   if (J) {
9356     for (d = 0; d < dim; d++) {
9357       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9358       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9359       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9360     }
9361     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9362              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9363              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9364     PetscLogFlops(18.0 + 12.0);
9365   }
9366   if (invJ) {
9367     const PetscReal invDet = -1.0/(*detJ);
9368 
9369     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9370     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9371     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9372     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9373     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9374     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9375     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9376     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9377     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9378     PetscLogFlops(37.0);
9379   }
9380   *detJ *= 8.0;
9381   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9382   PetscFunctionReturn(0);
9383 }
9384 
9385 #undef __FUNCT__
9386 #define __FUNCT__ "DMPlexComputeCellGeometry"
9387 /*@C
9388   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9389 
9390   Collective on DM
9391 
9392   Input Arguments:
9393 + dm   - the DM
9394 - cell - the cell
9395 
9396   Output Arguments:
9397 + v0   - the translation part of this affine transform
9398 . J    - the Jacobian of the transform to the reference element
9399 . invJ - the inverse of the Jacobian
9400 - detJ - the Jacobian determinant
9401 
9402   Level: advanced
9403 
9404 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9405 @*/
9406 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9407 {
9408   PetscInt       dim, coneSize;
9409   PetscErrorCode ierr;
9410 
9411   PetscFunctionBegin;
9412   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9413   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9414   switch (dim) {
9415   case 2:
9416     switch (coneSize) {
9417     case 3:
9418       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9419       break;
9420     case 4:
9421       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9422       break;
9423     default:
9424       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9425     }
9426     break;
9427   case 3:
9428     switch (coneSize) {
9429     case 4:
9430       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9431       break;
9432     case 8:
9433       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9434       break;
9435     default:
9436       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9437     }
9438     break;
9439   default:
9440     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9441   }
9442   PetscFunctionReturn(0);
9443 }
9444 
9445 #undef __FUNCT__
9446 #define __FUNCT__ "DMPlexGetFaceOrientation"
9447 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9448 {
9449   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9450   PetscBool      posOrient = PETSC_FALSE;
9451   const PetscInt debug     = 0;
9452   PetscInt       cellDim, faceSize, f;
9453   PetscErrorCode ierr;
9454 
9455   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9456   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9457 
9458   if (cellDim == numCorners-1) {
9459     /* Simplices */
9460     faceSize  = numCorners-1;
9461     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9462   } else if (cellDim == 1 && numCorners == 3) {
9463     /* Quadratic line */
9464     faceSize  = 1;
9465     posOrient = PETSC_TRUE;
9466   } else if (cellDim == 2 && numCorners == 4) {
9467     /* Quads */
9468     faceSize  = 2;
9469     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9470       posOrient = PETSC_TRUE;
9471     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9472       posOrient = PETSC_TRUE;
9473     } else {
9474       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9475         posOrient = PETSC_FALSE;
9476       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9477     }
9478   } else if (cellDim == 2 && numCorners == 6) {
9479     /* Quadratic triangle (I hate this) */
9480     /* Edges are determined by the first 2 vertices (corners of edges) */
9481     const PetscInt faceSizeTri = 3;
9482     PetscInt  sortedIndices[3], i, iFace;
9483     PetscBool found = PETSC_FALSE;
9484     PetscInt  faceVerticesTriSorted[9] = {
9485       0, 3,  4, /* bottom */
9486       1, 4,  5, /* right */
9487       2, 3,  5, /* left */
9488     };
9489     PetscInt  faceVerticesTri[9] = {
9490       0, 3,  4, /* bottom */
9491       1, 4,  5, /* right */
9492       2, 5,  3, /* left */
9493     };
9494 
9495     faceSize = faceSizeTri;
9496     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9497     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9498     for (iFace = 0; iFace < 3; ++iFace) {
9499       const PetscInt ii = iFace*faceSizeTri;
9500       PetscInt       fVertex, cVertex;
9501 
9502       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9503           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9504         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9505           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9506             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9507               faceVertices[fVertex] = origVertices[cVertex];
9508               break;
9509             }
9510           }
9511         }
9512         found = PETSC_TRUE;
9513         break;
9514       }
9515     }
9516     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9517     if (posOriented) {*posOriented = PETSC_TRUE;}
9518     PetscFunctionReturn(0);
9519   } else if (cellDim == 2 && numCorners == 9) {
9520     /* Quadratic quad (I hate this) */
9521     /* Edges are determined by the first 2 vertices (corners of edges) */
9522     const PetscInt faceSizeQuad = 3;
9523     PetscInt  sortedIndices[3], i, iFace;
9524     PetscBool found = PETSC_FALSE;
9525     PetscInt  faceVerticesQuadSorted[12] = {
9526       0, 1,  4, /* bottom */
9527       1, 2,  5, /* right */
9528       2, 3,  6, /* top */
9529       0, 3,  7, /* left */
9530     };
9531     PetscInt  faceVerticesQuad[12] = {
9532       0, 1,  4, /* bottom */
9533       1, 2,  5, /* right */
9534       2, 3,  6, /* top */
9535       3, 0,  7, /* left */
9536     };
9537 
9538     faceSize = faceSizeQuad;
9539     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9540     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9541     for (iFace = 0; iFace < 4; ++iFace) {
9542       const PetscInt ii = iFace*faceSizeQuad;
9543       PetscInt       fVertex, cVertex;
9544 
9545       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9546           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9547         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9548           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9549             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9550               faceVertices[fVertex] = origVertices[cVertex];
9551               break;
9552             }
9553           }
9554         }
9555         found = PETSC_TRUE;
9556         break;
9557       }
9558     }
9559     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9560     if (posOriented) {*posOriented = PETSC_TRUE;}
9561     PetscFunctionReturn(0);
9562   } else if (cellDim == 3 && numCorners == 8) {
9563     /* Hexes
9564        A hex is two oriented quads with the normal of the first
9565        pointing up at the second.
9566 
9567           7---6
9568          /|  /|
9569         4---5 |
9570         | 3-|-2
9571         |/  |/
9572         0---1
9573 
9574         Faces are determined by the first 4 vertices (corners of faces) */
9575     const PetscInt faceSizeHex = 4;
9576     PetscInt  sortedIndices[4], i, iFace;
9577     PetscBool found = PETSC_FALSE;
9578     PetscInt faceVerticesHexSorted[24] = {
9579       0, 1, 2, 3,  /* bottom */
9580       4, 5, 6, 7,  /* top */
9581       0, 1, 4, 5,  /* front */
9582       1, 2, 5, 6,  /* right */
9583       2, 3, 6, 7,  /* back */
9584       0, 3, 4, 7,  /* left */
9585     };
9586     PetscInt faceVerticesHex[24] = {
9587       3, 2, 1, 0,  /* bottom */
9588       4, 5, 6, 7,  /* top */
9589       0, 1, 5, 4,  /* front */
9590       1, 2, 6, 5,  /* right */
9591       2, 3, 7, 6,  /* back */
9592       3, 0, 4, 7,  /* left */
9593     };
9594 
9595     faceSize = faceSizeHex;
9596     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9597     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9598     for (iFace = 0; iFace < 6; ++iFace) {
9599       const PetscInt ii = iFace*faceSizeHex;
9600       PetscInt       fVertex, cVertex;
9601 
9602       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9603           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9604           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9605           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9606         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9607           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9608             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9609               faceVertices[fVertex] = origVertices[cVertex];
9610               break;
9611             }
9612           }
9613         }
9614         found = PETSC_TRUE;
9615         break;
9616       }
9617     }
9618     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9619     if (posOriented) {*posOriented = PETSC_TRUE;}
9620     PetscFunctionReturn(0);
9621   } else if (cellDim == 3 && numCorners == 10) {
9622     /* Quadratic tet */
9623     /* Faces are determined by the first 3 vertices (corners of faces) */
9624     const PetscInt faceSizeTet = 6;
9625     PetscInt  sortedIndices[6], i, iFace;
9626     PetscBool found = PETSC_FALSE;
9627     PetscInt faceVerticesTetSorted[24] = {
9628       0, 1, 2,  6, 7, 8, /* bottom */
9629       0, 3, 4,  6, 7, 9,  /* front */
9630       1, 4, 5,  7, 8, 9,  /* right */
9631       2, 3, 5,  6, 8, 9,  /* left */
9632     };
9633     PetscInt faceVerticesTet[24] = {
9634       0, 1, 2,  6, 7, 8, /* bottom */
9635       0, 4, 3,  6, 7, 9,  /* front */
9636       1, 5, 4,  7, 8, 9,  /* right */
9637       2, 3, 5,  8, 6, 9,  /* left */
9638     };
9639 
9640     faceSize = faceSizeTet;
9641     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9642     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9643     for (iFace=0; iFace < 4; ++iFace) {
9644       const PetscInt ii = iFace*faceSizeTet;
9645       PetscInt       fVertex, cVertex;
9646 
9647       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9648           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9649           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9650           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9651         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9652           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9653             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9654               faceVertices[fVertex] = origVertices[cVertex];
9655               break;
9656             }
9657           }
9658         }
9659         found = PETSC_TRUE;
9660         break;
9661       }
9662     }
9663     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9664     if (posOriented) {*posOriented = PETSC_TRUE;}
9665     PetscFunctionReturn(0);
9666   } else if (cellDim == 3 && numCorners == 27) {
9667     /* Quadratic hexes (I hate this)
9668        A hex is two oriented quads with the normal of the first
9669        pointing up at the second.
9670 
9671          7---6
9672         /|  /|
9673        4---5 |
9674        | 3-|-2
9675        |/  |/
9676        0---1
9677 
9678        Faces are determined by the first 4 vertices (corners of faces) */
9679     const PetscInt faceSizeQuadHex = 9;
9680     PetscInt  sortedIndices[9], i, iFace;
9681     PetscBool found = PETSC_FALSE;
9682     PetscInt faceVerticesQuadHexSorted[54] = {
9683       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9684       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9685       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9686       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9687       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9688       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9689     };
9690     PetscInt faceVerticesQuadHex[54] = {
9691       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9692       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9693       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9694       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9695       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9696       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9697     };
9698 
9699     faceSize = faceSizeQuadHex;
9700     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9701     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9702     for (iFace = 0; iFace < 6; ++iFace) {
9703       const PetscInt ii = iFace*faceSizeQuadHex;
9704       PetscInt       fVertex, cVertex;
9705 
9706       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9707           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9708           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9709           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9710         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9711           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9712             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9713               faceVertices[fVertex] = origVertices[cVertex];
9714               break;
9715             }
9716           }
9717         }
9718         found = PETSC_TRUE;
9719         break;
9720       }
9721     }
9722     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9723     if (posOriented) {*posOriented = PETSC_TRUE;}
9724     PetscFunctionReturn(0);
9725   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9726   if (!posOrient) {
9727     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9728     for (f = 0; f < faceSize; ++f) {
9729       faceVertices[f] = origVertices[faceSize-1 - f];
9730     }
9731   } else {
9732     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9733     for (f = 0; f < faceSize; ++f) {
9734       faceVertices[f] = origVertices[f];
9735     }
9736   }
9737   if (posOriented) {*posOriented = posOrient;}
9738   PetscFunctionReturn(0);
9739 }
9740 
9741 #undef __FUNCT__
9742 #define __FUNCT__ "DMPlexGetOrientedFace"
9743 /*
9744     Given a cell and a face, as a set of vertices,
9745       return the oriented face, as a set of vertices, in faceVertices
9746     The orientation is such that the face normal points out of the cell
9747 */
9748 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9749 {
9750   const PetscInt *cone = PETSC_NULL;
9751   PetscInt        coneSize, v, f, v2;
9752   PetscInt        oppositeVertex = -1;
9753   PetscErrorCode  ierr;
9754 
9755   PetscFunctionBegin;
9756   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9757   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9758   for (v = 0, v2 = 0; v < coneSize; ++v) {
9759     PetscBool found  = PETSC_FALSE;
9760 
9761     for (f = 0; f < faceSize; ++f) {
9762       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9763     }
9764     if (found) {
9765       indices[v2]      = v;
9766       origVertices[v2] = cone[v];
9767       ++v2;
9768     } else {
9769       oppositeVertex = v;
9770     }
9771   }
9772   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9773   PetscFunctionReturn(0);
9774 }
9775 
9776 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9777 {
9778   switch (i) {
9779   case 0:
9780     switch (j) {
9781     case 0: return 0;
9782     case 1:
9783       switch (k) {
9784       case 0: return 0;
9785       case 1: return 0;
9786       case 2: return 1;
9787       }
9788     case 2:
9789       switch (k) {
9790       case 0: return 0;
9791       case 1: return -1;
9792       case 2: return 0;
9793       }
9794     }
9795   case 1:
9796     switch (j) {
9797     case 0:
9798       switch (k) {
9799       case 0: return 0;
9800       case 1: return 0;
9801       case 2: return -1;
9802       }
9803     case 1: return 0;
9804     case 2:
9805       switch (k) {
9806       case 0: return 1;
9807       case 1: return 0;
9808       case 2: return 0;
9809       }
9810     }
9811   case 2:
9812     switch (j) {
9813     case 0:
9814       switch (k) {
9815       case 0: return 0;
9816       case 1: return 1;
9817       case 2: return 0;
9818       }
9819     case 1:
9820       switch (k) {
9821       case 0: return -1;
9822       case 1: return 0;
9823       case 2: return 0;
9824       }
9825     case 2: return 0;
9826     }
9827   }
9828   return 0;
9829 }
9830 
9831 #undef __FUNCT__
9832 #define __FUNCT__ "DMPlexCreateRigidBody"
9833 /*@C
9834   DMPlexCreateRigidBody - create rigid body modes from coordinates
9835 
9836   Collective on DM
9837 
9838   Input Arguments:
9839 + dm - the DM
9840 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9841 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9842 
9843   Output Argument:
9844 . sp - the null space
9845 
9846   Note: This is necessary to take account of Dirichlet conditions on the displacements
9847 
9848   Level: advanced
9849 
9850 .seealso: MatNullSpaceCreate()
9851 @*/
9852 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9853 {
9854   MPI_Comm       comm = ((PetscObject) dm)->comm;
9855   Vec            coordinates, localMode, mode[6];
9856   PetscSection   coordSection;
9857   PetscScalar   *coords;
9858   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9859   PetscErrorCode ierr;
9860 
9861   PetscFunctionBegin;
9862   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9863   if (dim == 1) {
9864     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9865     PetscFunctionReturn(0);
9866   }
9867   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9868   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9869   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9870   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9871   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9872   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9873   m    = (dim*(dim+1))/2;
9874   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9875   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9876   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9877   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9878   /* Assume P1 */
9879   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9880   for (d = 0; d < dim; ++d) {
9881     PetscScalar values[3] = {0.0, 0.0, 0.0};
9882 
9883     values[d] = 1.0;
9884     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9885     for (v = vStart; v < vEnd; ++v) {
9886       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9887     }
9888     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9889     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9890   }
9891   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9892   for (d = dim; d < dim*(dim+1)/2; ++d) {
9893     PetscInt i, j, k = dim > 2 ? d - dim : d;
9894 
9895     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9896     for (v = vStart; v < vEnd; ++v) {
9897       PetscScalar values[3] = {0.0, 0.0, 0.0};
9898       PetscInt    off;
9899 
9900       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9901       for (i = 0; i < dim; ++i) {
9902         for (j = 0; j < dim; ++j) {
9903           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9904         }
9905       }
9906       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9907     }
9908     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9909     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9910   }
9911   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9912   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9913   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9914   /* Orthonormalize system */
9915   for (i = dim; i < m; ++i) {
9916     PetscScalar dots[6];
9917 
9918     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9919     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9920     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9921     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9922   }
9923   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9924   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9925   PetscFunctionReturn(0);
9926 }
9927 
9928 #undef __FUNCT__
9929 #define __FUNCT__ "DMPlexGetHybridBounds"
9930 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9931 {
9932   DM_Plex       *mesh = (DM_Plex *) dm->data;
9933   PetscInt       dim;
9934   PetscErrorCode ierr;
9935 
9936   PetscFunctionBegin;
9937   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9938   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9939   if (cMax) *cMax = mesh->hybridPointMax[dim];
9940   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9941   if (eMax) *eMax = mesh->hybridPointMax[1];
9942   if (vMax) *vMax = mesh->hybridPointMax[0];
9943   PetscFunctionReturn(0);
9944 }
9945 
9946 #undef __FUNCT__
9947 #define __FUNCT__ "DMPlexSetHybridBounds"
9948 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9949 {
9950   DM_Plex       *mesh = (DM_Plex *) dm->data;
9951   PetscInt       dim;
9952   PetscErrorCode ierr;
9953 
9954   PetscFunctionBegin;
9955   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9956   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9957   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9958   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9959   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9960   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9961   PetscFunctionReturn(0);
9962 }
9963 
9964 #undef __FUNCT__
9965 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9966 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9967 {
9968   DM_Plex *mesh = (DM_Plex *) dm->data;
9969 
9970   PetscFunctionBegin;
9971   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9972   PetscValidPointer(cellHeight, 2);
9973   *cellHeight = mesh->vtkCellHeight;
9974   PetscFunctionReturn(0);
9975 }
9976 
9977 #undef __FUNCT__
9978 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9979 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9980 {
9981   DM_Plex *mesh = (DM_Plex *) dm->data;
9982 
9983   PetscFunctionBegin;
9984   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9985   mesh->vtkCellHeight = cellHeight;
9986   PetscFunctionReturn(0);
9987 }
9988 
9989 #undef __FUNCT__
9990 #define __FUNCT__ "DMPlexInsertFace_Private"
9991 /*
9992   DMPlexInsertFace_Private - Puts a face into the mesh
9993 
9994   Not collective
9995 
9996   Input Parameters:
9997   + dm              - The DMPlex
9998   . numFaceVertex   - The number of vertices in the face
9999   . faceVertices    - The vertices in the face for dm
10000   . subfaceVertices - The vertices in the face for subdm
10001   . numCorners      - The number of vertices in the cell
10002   . cell            - A cell in dm containing the face
10003   . subcell         - A cell in subdm containing the face
10004   . firstFace       - First face in the mesh
10005   - newFacePoint    - Next face in the mesh
10006 
10007   Output Parameters:
10008   . newFacePoint - Contains next face point number on input, updated on output
10009 
10010   Level: developer
10011 */
10012 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)
10013 {
10014   MPI_Comm        comm    = ((PetscObject) dm)->comm;
10015   DM_Plex     *submesh = (DM_Plex *) subdm->data;
10016   const PetscInt *faces;
10017   PetscInt        numFaces, coneSize;
10018   PetscErrorCode  ierr;
10019 
10020   PetscFunctionBegin;
10021   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
10022   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
10023 #if 0
10024   /* Cannot use this because support() has not been constructed yet */
10025   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10026 #else
10027   {
10028     PetscInt f;
10029 
10030     numFaces = 0;
10031     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
10032     for (f = firstFace; f < *newFacePoint; ++f) {
10033       PetscInt dof, off, d;
10034 
10035       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
10036       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
10037       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
10038       for (d = 0; d < dof; ++d) {
10039         const PetscInt p = submesh->cones[off+d];
10040         PetscInt       v;
10041 
10042         for (v = 0; v < numFaceVertices; ++v) {
10043           if (subfaceVertices[v] == p) break;
10044         }
10045         if (v == numFaceVertices) break;
10046       }
10047       if (d == dof) {
10048         numFaces = 1;
10049         ((PetscInt *) faces)[0] = f;
10050       }
10051     }
10052   }
10053 #endif
10054   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
10055   else if (numFaces == 1) {
10056     /* Add the other cell neighbor for this face */
10057     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
10058   } else {
10059     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
10060     PetscBool posOriented;
10061 
10062     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10063     origVertices = &orientedVertices[numFaceVertices];
10064     indices      = &orientedVertices[numFaceVertices*2];
10065     orientedSubVertices = &orientedVertices[numFaceVertices*3];
10066     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
10067     /* TODO: I know that routine should return a permutation, not the indices */
10068     for (v = 0; v < numFaceVertices; ++v) {
10069       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
10070       for (ov = 0; ov < numFaceVertices; ++ov) {
10071         if (orientedVertices[ov] == vertex) {
10072           orientedSubVertices[ov] = subvertex;
10073           break;
10074         }
10075       }
10076       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
10077     }
10078     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
10079     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
10080     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10081     ++(*newFacePoint);
10082   }
10083   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10084   PetscFunctionReturn(0);
10085 }
10086 
10087 #undef __FUNCT__
10088 #define __FUNCT__ "DMPlexCreateSubmesh"
10089 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
10090 {
10091   MPI_Comm        comm = ((PetscObject) dm)->comm;
10092   DM_Plex     *submesh;
10093   PetscBool       boundaryFaces = PETSC_FALSE;
10094   PetscSection    coordSection, subCoordSection;
10095   Vec             coordinates, subCoordinates;
10096   PetscScalar    *coords, *subCoords;
10097   IS              labelIS;
10098   const PetscInt *subVertices;
10099   PetscInt       *subVerticesActive, *tmpPoints;
10100   PetscInt       *subCells = PETSC_NULL;
10101   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
10102   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
10103   PetscInt        dim; /* Right now, do not specify dimension */
10104   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
10105   PetscErrorCode  ierr;
10106 
10107   PetscFunctionBegin;
10108   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10109   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10110   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10111   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
10112   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10113   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10114   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10115   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10116   subface = &face[maxConeSize];
10117   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
10118   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10119   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10120   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
10121   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
10122   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
10123   maxSubCells = numSubVertices;
10124   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
10125   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
10126   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
10127   for (v = 0; v < numSubVertices; ++v) {
10128     const PetscInt vertex = subVertices[v];
10129     PetscInt *star = PETSC_NULL;
10130     PetscInt  starSize, numCells = 0;
10131 
10132     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10133     for (p = 0; p < starSize*2; p += 2) {
10134       const PetscInt point = star[p];
10135       if ((point >= cStart) && (point < cEnd)) {
10136         star[numCells++] = point;
10137       }
10138     }
10139     numOldSubCells = numSubCells;
10140     for (c = 0; c < numCells; ++c) {
10141       const PetscInt cell    = star[c];
10142       PetscInt      *closure = PETSC_NULL;
10143       PetscInt       closureSize, numCorners = 0, faceSize = 0;
10144       PetscInt       cellLoc;
10145 
10146       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
10147       if (cellLoc >= 0) continue;
10148       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10149       for (p = 0; p < closureSize*2; p += 2) {
10150         const PetscInt point = closure[p];
10151         if ((point >= vStart) && (point < vEnd)) {
10152           closure[numCorners++] = point;
10153         }
10154       }
10155       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
10156       for (corner = 0; corner < numCorners; ++corner) {
10157         const PetscInt cellVertex = closure[corner];
10158         PetscInt       subVertex;
10159 
10160         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
10161         if (subVertex >= 0) { /* contains submesh vertex */
10162           for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10163           if (i == faceSize) {
10164             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
10165             face[faceSize]    = cellVertex;
10166             subface[faceSize] = subVertex;
10167             ++faceSize;
10168           }
10169         }
10170       }
10171       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10172       if (faceSize >= nFV) {
10173         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10174         if (numSubCells >= maxSubCells) {
10175           PetscInt *tmpCells;
10176           maxSubCells *= 2;
10177           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
10178           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
10179           ierr = PetscFree(subCells);CHKERRQ(ierr);
10180           subCells = tmpCells;
10181         }
10182         /* TOOD: Maybe overestimate then squeeze out empty faces */
10183         if (faceSize > nFV) {
10184           /* TODO: This is tricky. Maybe just add all faces */
10185           numSubFaces++;
10186         } else {
10187           numSubFaces++;
10188         }
10189         for (f = 0; f < faceSize; ++f) {
10190           subVerticesActive[subface[f]] = 1;
10191         }
10192         subCells[numSubCells++] = cell;
10193       }
10194     }
10195     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10196     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
10197   }
10198   /* Pick out active subvertices */
10199   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
10200     if (subVerticesActive[v]) {
10201       subVerticesActive[numSubVerticesActive++] = subVertices[v];
10202     }
10203   }
10204   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
10205   /* Set cone sizes */
10206   firstSubVertex = numSubCells;
10207   firstSubFace   = numSubCells+numSubVerticesActive;
10208   newFacePoint   = firstSubFace;
10209   for (c = 0; c < numSubCells; ++c) {
10210     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
10211   }
10212   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
10213     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
10214   }
10215   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
10216   /* Create face cones */
10217   for (c = 0; c < numSubCells; ++c) {
10218     const PetscInt cell    = subCells[c];
10219     PetscInt      *closure = PETSC_NULL;
10220     PetscInt       closureSize, numCorners = 0, faceSize = 0;
10221 
10222     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10223     for (p = 0; p < closureSize*2; p += 2) {
10224       const PetscInt point = closure[p];
10225       if ((point >= vStart) && (point < vEnd)) {
10226         closure[numCorners++] = point;
10227       }
10228     }
10229     for (corner = 0; corner < numCorners; ++corner) {
10230       const PetscInt cellVertex = closure[corner];
10231       PetscInt       subVertex;
10232 
10233       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
10234       if (subVertex >= 0) { /* contains submesh vertex */
10235         for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10236         if (i == faceSize) {
10237           face[faceSize]    = cellVertex;
10238           subface[faceSize] = numSubCells+subVertex;
10239           ++faceSize;
10240         }
10241       }
10242     }
10243     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10244     if (faceSize >= nFV) {
10245       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10246       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
10247       /*   We have to take all the faces, and discard those in the interior */
10248       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
10249 #if 0
10250       /* This object just calls insert on each face that comes from subsets() */
10251       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
10252       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
10253       PointArray                          faceVec(face->begin(), face->end());
10254 
10255       subsets(faceVec, nFV, inserter);
10256 #endif
10257       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10258     }
10259   }
10260   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
10261   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
10262   /* Build coordinates */
10263   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10264   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10265   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
10266   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10267   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10268     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10269   }
10270   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10271   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10272   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
10273   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10274   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10275   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10276   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10277   for (v = 0; v < numSubVerticesActive; ++v) {
10278     const PetscInt vertex    = subVerticesActive[v];
10279     const PetscInt subVertex = firstSubVertex+v;
10280     PetscInt dof, off, sdof, soff;
10281 
10282     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10283     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10284     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10285     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10286     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10287     for (d = 0; d < dof; ++d) {
10288       subCoords[soff+d] = coords[off+d];
10289     }
10290   }
10291   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10292   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10293   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
10294   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10295 
10296   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
10297   /* Create map from submesh points to original mesh points */
10298   submesh = (DM_Plex *) (*subdm)->data;
10299   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10300   for (c = 0; c < numSubCells; ++c) {
10301     tmpPoints[c] = subCells[c];
10302   }
10303   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
10304     tmpPoints[v] = subVerticesActive[v-numSubCells];
10305   }
10306   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
10307 
10308   ierr = PetscFree(subCells);CHKERRQ(ierr);
10309   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10310   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10311   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10312   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10313   PetscFunctionReturn(0);
10314 }
10315 
10316 #undef __FUNCT__
10317 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10318 /* We can easily have a form that takes an IS instead */
10319 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10320 {
10321   PetscSection   section, globalSection;
10322   PetscInt      *numbers, p;
10323   PetscErrorCode ierr;
10324 
10325   PetscFunctionBegin;
10326   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10327   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10328   for (p = pStart; p < pEnd; ++p) {
10329     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10330   }
10331   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10332   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10333   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10334   for (p = pStart; p < pEnd; ++p) {
10335     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10336   }
10337   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10338   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10339   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10340   PetscFunctionReturn(0);
10341 }
10342 
10343 #undef __FUNCT__
10344 #define __FUNCT__ "DMPlexGetCellNumbering"
10345 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10346 {
10347   DM_Plex    *mesh = (DM_Plex *) dm->data;
10348   PetscInt       cellHeight, cStart, cEnd, cMax;
10349   PetscErrorCode ierr;
10350 
10351   PetscFunctionBegin;
10352   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10353   if (!mesh->globalCellNumbers) {
10354     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10355     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10356     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10357     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10358     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10359   }
10360   *globalCellNumbers = mesh->globalCellNumbers;
10361   PetscFunctionReturn(0);
10362 }
10363 
10364 #undef __FUNCT__
10365 #define __FUNCT__ "DMPlexGetVertexNumbering"
10366 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10367 {
10368   DM_Plex    *mesh = (DM_Plex *) dm->data;
10369   PetscInt       vStart, vEnd, vMax;
10370   PetscErrorCode ierr;
10371 
10372   PetscFunctionBegin;
10373   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10374   if (!mesh->globalVertexNumbers) {
10375     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10376     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10377     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10378     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10379   }
10380   *globalVertexNumbers = mesh->globalVertexNumbers;
10381   PetscFunctionReturn(0);
10382 }
10383 
10384 #undef __FUNCT__
10385 #define __FUNCT__ "DMPlexGetSubpointMap"
10386 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10387 {
10388   DM_Plex *mesh = (DM_Plex *) dm->data;
10389 
10390   PetscFunctionBegin;
10391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10392   PetscValidPointer(subpointMap, 2);
10393   *subpointMap = mesh->subpointMap;
10394   PetscFunctionReturn(0);
10395 }
10396 
10397 #undef __FUNCT__
10398 #define __FUNCT__ "DMPlexSetSubpointMap"
10399 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10400 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10401 {
10402   DM_Plex *mesh = (DM_Plex *) dm->data;
10403 
10404   PetscFunctionBegin;
10405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10406   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10407   mesh->subpointMap = subpointMap;
10408   PetscFunctionReturn(0);
10409 }
10410 
10411 #undef __FUNCT__
10412 #define __FUNCT__ "DMPlexGetScale"
10413 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10414 {
10415   DM_Plex *mesh = (DM_Plex *) dm->data;
10416 
10417   PetscFunctionBegin;
10418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10419   PetscValidPointer(scale, 3);
10420   *scale = mesh->scale[unit];
10421   PetscFunctionReturn(0);
10422 }
10423 
10424 #undef __FUNCT__
10425 #define __FUNCT__ "DMPlexSetScale"
10426 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10427 {
10428   DM_Plex *mesh = (DM_Plex *) dm->data;
10429 
10430   PetscFunctionBegin;
10431   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10432   mesh->scale[unit] = scale;
10433   PetscFunctionReturn(0);
10434 }
10435 
10436 
10437 /*******************************************************************************
10438 This should be in a separate Discretization object, but I am not sure how to lay
10439 it out yet, so I am stuffing things here while I experiment.
10440 *******************************************************************************/
10441 #undef __FUNCT__
10442 #define __FUNCT__ "DMPlexSetFEMIntegration"
10443 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10444                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10445                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10446                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10447                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10448                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], 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[]),
10452                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10453                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10454                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10455                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10456                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10457                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10458                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10459                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10460 {
10461   DM_Plex *mesh = (DM_Plex *) dm->data;
10462 
10463   PetscFunctionBegin;
10464   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10465   mesh->integrateResidualFEM       = integrateResidualFEM;
10466   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10467   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10468   PetscFunctionReturn(0);
10469 }
10470 
10471 #undef __FUNCT__
10472 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10473 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10474 {
10475   Vec            coordinates;
10476   PetscSection   section, cSection;
10477   PetscInt       dim, vStart, vEnd, v, c, d;
10478   PetscScalar   *values, *cArray;
10479   PetscReal     *coords;
10480   PetscErrorCode ierr;
10481 
10482   PetscFunctionBegin;
10483   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10484   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10485   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10486   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10487   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10488   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10489   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10490   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10491   for (v = vStart; v < vEnd; ++v) {
10492     PetscInt dof, off;
10493 
10494     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10495     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10496     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10497     for (d = 0; d < dof; ++d) {
10498       coords[d] = PetscRealPart(cArray[off+d]);
10499     }
10500     for (c = 0; c < numComp; ++c) {
10501       values[c] = (*funcs[c])(coords);
10502     }
10503     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10504   }
10505   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10506   /* Temporary, must be replaced by a projection on the finite element basis */
10507   {
10508     PetscInt eStart = 0, eEnd = 0, e, depth;
10509 
10510     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10511     --depth;
10512     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10513     for (e = eStart; e < eEnd; ++e) {
10514       const PetscInt *cone = PETSC_NULL;
10515       PetscInt        coneSize, d;
10516       PetscScalar    *coordsA, *coordsB;
10517 
10518       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10519       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10520       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10521       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10522       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10523       for (d = 0; d < dim; ++d) {
10524         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10525       }
10526       for (c = 0; c < numComp; ++c) {
10527         values[c] = (*funcs[c])(coords);
10528       }
10529       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10530     }
10531   }
10532 
10533   ierr = PetscFree(coords);CHKERRQ(ierr);
10534   ierr = PetscFree(values);CHKERRQ(ierr);
10535 #if 0
10536   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10537   PetscReal      detJ;
10538 
10539   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10540   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10541   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10542 
10543   for (PetscInt c = cStart; c < cEnd; ++c) {
10544     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10545     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10546     const int                          oSize   = pV.getSize();
10547     int                                v       = 0;
10548 
10549     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10550     for (PetscInt cl = 0; cl < oSize; ++cl) {
10551       const PetscInt fDim;
10552 
10553       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10554       if (pointDim) {
10555         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10556           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10557         }
10558       }
10559     }
10560     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10561     pV.clear();
10562   }
10563   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10564   ierr = PetscFree(values);CHKERRQ(ierr);
10565 #endif
10566   PetscFunctionReturn(0);
10567 }
10568 
10569 #undef __FUNCT__
10570 #define __FUNCT__ "DMPlexProjectFunction"
10571 /*@C
10572   DMPlexProjectFunction - This projects the given function into the function space provided.
10573 
10574   Input Parameters:
10575 + dm      - The DM
10576 . numComp - The number of components (functions)
10577 . funcs   - The coordinate functions to evaluate
10578 - mode    - The insertion mode for values
10579 
10580   Output Parameter:
10581 . X - vector
10582 
10583   Level: developer
10584 
10585   Note:
10586   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10587   We will eventually fix it.
10588 
10589 ,seealso: DMPlexComputeL2Diff()
10590 */
10591 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10592 {
10593   Vec            localX;
10594   PetscErrorCode ierr;
10595 
10596   PetscFunctionBegin;
10597   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10598   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10599   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10600   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10601   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10602   PetscFunctionReturn(0);
10603 }
10604 
10605 #undef __FUNCT__
10606 #define __FUNCT__ "DMPlexComputeL2Diff"
10607 /*@C
10608   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10609 
10610   Input Parameters:
10611 + dm    - The DM
10612 . quad  - The PetscQuadrature object for each field
10613 . funcs - The functions to evaluate for each field component
10614 - X     - The coefficient vector u_h
10615 
10616   Output Parameter:
10617 . diff - The diff ||u - u_h||_2
10618 
10619   Level: developer
10620 
10621 .seealso: DMPlexProjectFunction()
10622 */
10623 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10624 {
10625   const PetscInt   debug = 0;
10626   PetscSection     section;
10627   Vec              localX;
10628   PetscReal       *coords, *v0, *J, *invJ, detJ;
10629   PetscReal        localDiff = 0.0;
10630   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10631   PetscErrorCode   ierr;
10632 
10633   PetscFunctionBegin;
10634   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10635   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10636   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10637   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10638   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10639   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10640   for (field = 0; field < numFields; ++field) {
10641     numComponents += quad[field].numComponents;
10642   }
10643   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10644   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10645   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10646   for (c = cStart; c < cEnd; ++c) {
10647     const PetscScalar *x;
10648     PetscReal          elemDiff = 0.0;
10649 
10650     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10651     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10652     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10653 
10654     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10655       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10656       const PetscReal *quadPoints    = quad[field].quadPoints;
10657       const PetscReal *quadWeights   = quad[field].quadWeights;
10658       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10659       const PetscInt   numBasisComps = quad[field].numComponents;
10660       const PetscReal *basis         = quad[field].basis;
10661       PetscInt         q, d, e, fc, f;
10662 
10663       if (debug) {
10664         char title[1024];
10665         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10666         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10667       }
10668       for (q = 0; q < numQuadPoints; ++q) {
10669         for (d = 0; d < dim; d++) {
10670           coords[d] = v0[d];
10671           for (e = 0; e < dim; e++) {
10672             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10673           }
10674         }
10675         for (fc = 0; fc < numBasisComps; ++fc) {
10676           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10677           PetscReal       interpolant = 0.0;
10678           for (f = 0; f < numBasisFuncs; ++f) {
10679             const PetscInt fidx = f*numBasisComps+fc;
10680             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10681           }
10682           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10683           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10684         }
10685       }
10686       comp        += numBasisComps;
10687       fieldOffset += numBasisFuncs*numBasisComps;
10688     }
10689     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10690     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10691     localDiff += elemDiff;
10692   }
10693   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10694   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10695   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10696   *diff = PetscSqrtReal(*diff);
10697   PetscFunctionReturn(0);
10698 }
10699 
10700 #undef __FUNCT__
10701 #define __FUNCT__ "DMPlexComputeResidualFEM"
10702 /*@
10703   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10704 
10705   Input Parameters:
10706 + dm - The mesh
10707 . X  - Local input vector
10708 - user - The user context
10709 
10710   Output Parameter:
10711 . F  - Local output vector
10712 
10713   Note:
10714   The second member of the user context must be an FEMContext.
10715 
10716   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10717   like a GPU, or vectorize on a multicore machine.
10718 
10719 .seealso: DMPlexComputeJacobianActionFEM()
10720 */
10721 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10722 {
10723   DM_Plex      *mesh = (DM_Plex *) dm->data;
10724   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10725   PetscQuadrature *quad = fem->quad;
10726   PetscSection     section;
10727   PetscReal       *v0, *J, *invJ, *detJ;
10728   PetscScalar     *elemVec, *u;
10729   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10730   PetscInt         cellDof = 0, numComponents = 0;
10731   PetscErrorCode   ierr;
10732 
10733   PetscFunctionBegin;
10734   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10735   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10736   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10737   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10738   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10739   numCells = cEnd - cStart;
10740   for (field = 0; field < numFields; ++field) {
10741     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10742     numComponents += quad[field].numComponents;
10743   }
10744   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10745   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10746   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);
10747   for (c = cStart; c < cEnd; ++c) {
10748     const PetscScalar *x;
10749     PetscInt           i;
10750 
10751     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10752     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10753     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10754 
10755     for (i = 0; i < cellDof; ++i) {
10756       u[c*cellDof+i] = x[i];
10757     }
10758     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10759   }
10760   for (field = 0; field < numFields; ++field) {
10761     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10762     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10763     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10764     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10765     /* Conforming batches */
10766     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10767     PetscInt numBlocks  = 1;
10768     PetscInt batchSize  = numBlocks * blockSize;
10769     PetscInt numBatches = numBatchesTmp;
10770     PetscInt numChunks  = numCells / (numBatches*batchSize);
10771     /* Remainder */
10772     PetscInt numRemainder = numCells % (numBatches * batchSize);
10773     PetscInt offset       = numCells - numRemainder;
10774 
10775     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10776     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10777                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10778   }
10779   for (c = cStart; c < cEnd; ++c) {
10780     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10781     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10782   }
10783   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10784   if (mesh->printFEM) {
10785     PetscMPIInt rank, numProcs;
10786     PetscInt    p;
10787 
10788     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10789     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10790     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10791     for (p = 0; p < numProcs; ++p) {
10792       if (p == rank) {
10793         Vec f;
10794 
10795         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10796         ierr = VecCopy(F, f);CHKERRQ(ierr);
10797         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10798         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10799         ierr = VecDestroy(&f);CHKERRQ(ierr);
10800         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10801       }
10802       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10803     }
10804   }
10805   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10806   PetscFunctionReturn(0);
10807 }
10808 
10809 #undef __FUNCT__
10810 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10811 /*@C
10812   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10813 
10814   Input Parameters:
10815 + dm - The mesh
10816 . J  - The Jacobian shell matrix
10817 . X  - Local input vector
10818 - user - The user context
10819 
10820   Output Parameter:
10821 . F  - Local output vector
10822 
10823   Note:
10824   The second member of the user context must be an FEMContext.
10825 
10826   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10827   like a GPU, or vectorize on a multicore machine.
10828 
10829 .seealso: DMPlexComputeResidualFEM()
10830 */
10831 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10832 {
10833   DM_Plex      *mesh = (DM_Plex *) dm->data;
10834   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10835   PetscQuadrature *quad = fem->quad;
10836   PetscSection     section;
10837   JacActionCtx    *jctx;
10838   PetscReal       *v0, *J, *invJ, *detJ;
10839   PetscScalar     *elemVec, *u, *a;
10840   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10841   PetscInt         cellDof = 0;
10842   PetscErrorCode   ierr;
10843 
10844   PetscFunctionBegin;
10845   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10846   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10847   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10848   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10849   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10850   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10851   numCells = cEnd - cStart;
10852   for (field = 0; field < numFields; ++field) {
10853     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10854   }
10855   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10856   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);
10857   for (c = cStart; c < cEnd; ++c) {
10858     const PetscScalar *x;
10859     PetscInt           i;
10860 
10861     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10862     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10863     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10864     for (i = 0; i < cellDof; ++i) {
10865       u[c*cellDof+i] = x[i];
10866     }
10867     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10868     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10869     for (i = 0; i < cellDof; ++i) {
10870       a[c*cellDof+i] = x[i];
10871     }
10872     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10873   }
10874   for (field = 0; field < numFields; ++field) {
10875     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10876     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10877     /* Conforming batches */
10878     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10879     PetscInt numBlocks  = 1;
10880     PetscInt batchSize  = numBlocks * blockSize;
10881     PetscInt numBatches = numBatchesTmp;
10882     PetscInt numChunks  = numCells / (numBatches*batchSize);
10883     /* Remainder */
10884     PetscInt numRemainder = numCells % (numBatches * batchSize);
10885     PetscInt offset       = numCells - numRemainder;
10886 
10887     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);
10888     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],
10889                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10890   }
10891   for (c = cStart; c < cEnd; ++c) {
10892     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10893     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10894   }
10895   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10896   if (mesh->printFEM) {
10897     PetscMPIInt rank, numProcs;
10898     PetscInt    p;
10899 
10900     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10901     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10902     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10903     for (p = 0; p < numProcs; ++p) {
10904       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10905       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10906     }
10907   }
10908   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10909   PetscFunctionReturn(0);
10910 }
10911 
10912 #undef __FUNCT__
10913 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10914 /*@
10915   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10916 
10917   Input Parameters:
10918 + dm - The mesh
10919 . X  - Local input vector
10920 - user - The user context
10921 
10922   Output Parameter:
10923 . Jac  - Jacobian matrix
10924 
10925   Note:
10926   The second member of the user context must be an FEMContext.
10927 
10928   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10929   like a GPU, or vectorize on a multicore machine.
10930 
10931 .seealso: FormFunctionLocal()
10932 */
10933 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10934 {
10935   DM_Plex      *mesh = (DM_Plex *) dm->data;
10936   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10937   PetscQuadrature *quad = fem->quad;
10938   PetscSection     section;
10939   PetscReal       *v0, *J, *invJ, *detJ;
10940   PetscScalar     *elemMat, *u;
10941   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10942   PetscInt         cellDof = 0, numComponents = 0;
10943   PetscBool        isShell;
10944   PetscErrorCode   ierr;
10945 
10946   PetscFunctionBegin;
10947   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10948   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10949   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10950   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10951   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10952   numCells = cEnd - cStart;
10953   for (field = 0; field < numFields; ++field) {
10954     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10955     numComponents += quad[field].numComponents;
10956   }
10957   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10958   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10959   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);
10960   for (c = cStart; c < cEnd; ++c) {
10961     const PetscScalar *x;
10962     PetscInt           i;
10963 
10964     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10965     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10966     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10967 
10968     for (i = 0; i < cellDof; ++i) {
10969       u[c*cellDof+i] = x[i];
10970     }
10971     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10972   }
10973   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10974   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10975     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10976     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10977     PetscInt       fieldJ;
10978 
10979     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10980       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10981       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10982       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10983       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10984       /* Conforming batches */
10985       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10986       PetscInt numBlocks  = 1;
10987       PetscInt batchSize  = numBlocks * blockSize;
10988       PetscInt numBatches = numBatchesTmp;
10989       PetscInt numChunks  = numCells / (numBatches*batchSize);
10990       /* Remainder */
10991       PetscInt numRemainder = numCells % (numBatches * batchSize);
10992       PetscInt offset       = numCells - numRemainder;
10993 
10994       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10995       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10996                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10997     }
10998   }
10999   for (c = cStart; c < cEnd; ++c) {
11000     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
11001     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
11002   }
11003   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
11004 
11005   /* Assemble matrix, using the 2-step process:
11006        MatAssemblyBegin(), MatAssemblyEnd(). */
11007   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11008   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11009 
11010   if (mesh->printFEM) {
11011     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
11012     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
11013     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
11014   }
11015   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11016   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
11017   if (isShell) {
11018     JacActionCtx *jctx;
11019 
11020     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
11021     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
11022   }
11023   *str = SAME_NONZERO_PATTERN;
11024   PetscFunctionReturn(0);
11025 }
11026 
11027 
11028 #undef __FUNCT__
11029 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
11030 /*@C
11031   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
11032   the local section and an SF describing the section point overlap.
11033 
11034   Input Parameters:
11035   + s - The PetscSection for the local field layout
11036   . sf - The SF describing parallel layout of the section points
11037   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
11038   . label - The label specifying the points
11039   - labelValue - The label stratum specifying the points
11040 
11041   Output Parameter:
11042   . gsection - The PetscSection for the global field layout
11043 
11044   Note: This gives negative sizes and offsets to points not owned by this process
11045 
11046   Level: developer
11047 
11048 .seealso: PetscSectionCreate()
11049 @*/
11050 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
11051 {
11052   PetscInt      *neg;
11053   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
11054   PetscErrorCode ierr;
11055 
11056   PetscFunctionBegin;
11057   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
11058   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
11059   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
11060   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
11061   /* Mark ghost points with negative dof */
11062   for (p = pStart; p < pEnd; ++p) {
11063     PetscInt value;
11064 
11065     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11066     if (value != labelValue) continue;
11067     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11068     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11069     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11070     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11071     neg[p-pStart] = -(dof+1);
11072   }
11073   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11074   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11075   if (nroots >= 0) {
11076     if (nroots > pEnd - pStart) {
11077       PetscInt *tmpDof;
11078       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11079       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11080       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11081       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11082       for (p = pStart; p < pEnd; ++p) {
11083         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
11084       }
11085       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11086     } else {
11087       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11088       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11089     }
11090   }
11091   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11092   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11093     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11094     (*gsection)->atlasOff[p] = off;
11095     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11096   }
11097   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11098   globalOff -= off;
11099   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11100     (*gsection)->atlasOff[p] += globalOff;
11101     neg[p] = -((*gsection)->atlasOff[p]+1);
11102   }
11103   /* Put in negative offsets for ghost points */
11104   if (nroots >= 0) {
11105     if (nroots > pEnd - pStart) {
11106       PetscInt *tmpOff;
11107       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11108       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11109       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11110       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11111       for (p = pStart; p < pEnd; ++p) {
11112         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
11113       }
11114       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11115     } else {
11116       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11117       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11118     }
11119   }
11120   ierr = PetscFree(neg);CHKERRQ(ierr);
11121   PetscFunctionReturn(0);
11122 }
11123