xref: /petsc/src/dm/impls/plex/plex.c (revision 31ea7b403118ea130508732fc619463e04d89a34)
1 #include <petsc-private/pleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 
4 /* Logging support */
5 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
6 
7 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
8 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "VecView_Plex_Local"
12 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
13 {
14   DM             dm;
15   PetscBool      isvtk;
16   PetscErrorCode ierr;
17 
18   PetscFunctionBegin;
19   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
20   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
21   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
22   if (isvtk) {
23     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
24     PetscSection            section;
25     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
26 
27     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
28     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
29     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, PETSC_NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, PETSC_NULL);CHKERRQ(ierr);
32     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
33     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
34     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
35     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
36     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
37     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
38       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
39     } else if (cdof && vdof) {
40       SETERRQ(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
41     } else if (cdof) {
42       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
43        * vector or just happens to have the same number of dofs as the dimension. */
44       if (cdof == dim) {
45         ft = PETSC_VTK_CELL_VECTOR_FIELD;
46       } else {
47         ft = PETSC_VTK_CELL_FIELD;
48       }
49     } else if (vdof) {
50       if (vdof == dim) {
51         ft = PETSC_VTK_POINT_VECTOR_FIELD;
52       } else {
53         ft = PETSC_VTK_POINT_FIELD;
54       }
55     } else SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
56 
57     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
58     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
59     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
60   } else {
61     PetscBool isseq;
62 
63     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
64     if (isseq) {
65       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
66     } else {
67       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "VecView_Plex"
75 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
76 {
77   DM             dm;
78   PetscBool      isvtk;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
83   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
84   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
85   if (isvtk) {
86     Vec        locv;
87     const char *name;
88 
89     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
90     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
91     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
92     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
95     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
96   } else {
97     PetscBool isseq;
98 
99     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
100     if (isseq) {
101       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
102     } else {
103       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
104     }
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "DMPlexView_Ascii"
111 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
112 {
113   DM_Plex           *mesh = (DM_Plex*) dm->data;
114   DM                cdm;
115   DMLabel           markers;
116   PetscSection      coordSection;
117   Vec               coordinates;
118   PetscViewerFormat format;
119   PetscErrorCode    ierr;
120 
121   PetscFunctionBegin;
122   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
123   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
124   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
125   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
126   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
127     const char  *name;
128     PetscInt    maxConeSize, maxSupportSize;
129     PetscInt    pStart, pEnd, p;
130     PetscMPIInt rank, size;
131 
132     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
133     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
134     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
135     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
136     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
137     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
138     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
142     for (p = pStart; p < pEnd; ++p) {
143       PetscInt dof, off, s;
144 
145       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
146       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
147       for (s = off; s < off+dof; ++s) {
148         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
149       }
150     }
151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
152     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
153     for (p = pStart; p < pEnd; ++p) {
154       PetscInt dof, off, c;
155 
156       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
157       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
158       for (c = off; c < off+dof; ++c) {
159         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
160       }
161     }
162     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
163     ierr = PetscSectionGetChart(coordSection, &pStart, PETSC_NULL);CHKERRQ(ierr);
164     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
165     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
166     ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
167     if (size > 1) {
168       PetscSF sf;
169 
170       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
171       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
172     }
173     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
174   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
175     const char  *name;
176     const char  *colors[3] = {"red", "blue", "green"};
177     const int   numColors  = 3;
178     PetscReal   scale      = 2.0;
179     PetscScalar *coords;
180     PetscInt    depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
181     PetscMPIInt rank, size;
182 
183     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
184     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
185     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
186     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
187     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
188     ierr = PetscViewerASCIIPrintf(viewer, "\
189 \\documentclass[crop,multi=false]{standalone}\n\n\
190 \\usepackage{tikz}\n\
191 \\usepackage{pgflibraryshapes}\n\
192 \\usetikzlibrary{backgrounds}\n\
193 \\usetikzlibrary{arrows}\n\
194 \\begin{document}\n\
195 \\section{%s}\n\
196 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
197     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
198     for (p = 0; p < size; ++p) {
199       if (p > 0 && p == size-1) {
200         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
201       } else if (p > 0) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
203       }
204       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
205     }
206     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
207 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
208     /* Plot vertices */
209     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
210     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
211     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
212     for (v = vStart; v < vEnd; ++v) {
213       PetscInt off, dof, d;
214 
215       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
216       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
217       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
218       for (d = 0; d < dof; ++d) {
219         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
220         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
221       }
222       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
223     }
224     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
225     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
226     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
227     /* Plot edges */
228     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
229     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
230     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
231     for (e = eStart; e < eEnd; ++e) {
232       const PetscInt *cone;
233       PetscInt       coneSize, offA, offB, dof, d;
234 
235       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
236       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
237       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
238       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
239       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
240       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
241       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
242       for (d = 0; d < dof; ++d) {
243         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
244         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
245       }
246       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
247     }
248     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
249     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
250     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
251     /* Plot cells */
252     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
253     for (c = cStart; c < cEnd; ++c) {
254       PetscInt *closure = PETSC_NULL;
255       PetscInt closureSize, firstPoint = -1;
256 
257       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
258       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
259       for (p = 0; p < closureSize*2; p += 2) {
260         const PetscInt point = closure[p];
261 
262         if ((point < vStart) || (point >= vEnd)) continue;
263         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
264         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
265         if (firstPoint < 0) firstPoint = point;
266       }
267       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
268       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
269       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
270     }
271     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
272     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
273     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
274   } else {
275     MPI_Comm    comm = ((PetscObject) dm)->comm;
276     PetscInt    *sizes;
277     PetscInt    locDepth, depth, dim, d;
278     PetscInt    pStart, pEnd, p;
279     PetscMPIInt size;
280 
281     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
282     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
283     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
284     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
285     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
286     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
287     if (depth == 1) {
288       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
289       pEnd = pEnd - pStart;
290       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
291       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
292       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
293       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
294       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
295       pEnd = pEnd - pStart;
296       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
297       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
298       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
299       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
300     } else {
301       for (d = 0; d <= dim; d++) {
302         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
303         pEnd = pEnd - pStart;
304         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
305         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
306         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
307         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
308       }
309     }
310     ierr = PetscFree(sizes);CHKERRQ(ierr);
311   }
312   PetscFunctionReturn(0);
313 }
314 
315 #undef __FUNCT__
316 #define __FUNCT__ "DMView_Plex"
317 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
318 {
319   PetscBool      iascii, isbinary;
320   PetscErrorCode ierr;
321 
322   PetscFunctionBegin;
323   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
324   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
325   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
326   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
327   if (iascii) {
328     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
329 #if 0
330   } else if (isbinary) {
331     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
332 #endif
333   }
334   PetscFunctionReturn(0);
335 }
336 
337 #undef __FUNCT__
338 #define __FUNCT__ "DMDestroy_Plex"
339 PetscErrorCode DMDestroy_Plex(DM dm)
340 {
341   DM_Plex        *mesh = (DM_Plex*) dm->data;
342   DMLabel        next  = mesh->labels;
343   PetscErrorCode ierr;
344 
345   PetscFunctionBegin;
346   if (--mesh->refct > 0) PetscFunctionReturn(0);
347   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
348   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
349   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
350   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
352   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
353   while (next) {
354     DMLabel tmp = next->next;
355 
356     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
357     next = tmp;
358   }
359   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
360   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
361   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
362   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
363   ierr = PetscFree(mesh);CHKERRQ(ierr);
364   PetscFunctionReturn(0);
365 }
366 
367 #undef __FUNCT__
368 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
369 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
370 {
371   const PetscInt *support = PETSC_NULL;
372   PetscInt       numAdj   = 0, maxAdjSize = *adjSize, supportSize, s;
373   PetscErrorCode ierr;
374 
375   PetscFunctionBegin;
376   if (useClosure) {
377     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
378     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
379     for (s = 0; s < supportSize; ++s) {
380       const PetscInt *cone = PETSC_NULL;
381       PetscInt       coneSize, c, q;
382 
383       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
384       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
385       for (c = 0; c < coneSize; ++c) {
386         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
387           if (cone[c] == adj[q]) break;
388         }
389         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
390       }
391     }
392   } else {
393     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
394     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
395     for (s = 0; s < supportSize; ++s) {
396       const PetscInt *cone = PETSC_NULL;
397       PetscInt       coneSize, c, q;
398 
399       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
400       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
401       for (c = 0; c < coneSize; ++c) {
402         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
403           if (cone[c] == adj[q]) break;
404         }
405         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
406       }
407     }
408   }
409   *adjSize = numAdj;
410   PetscFunctionReturn(0);
411 }
412 
413 #undef __FUNCT__
414 #define __FUNCT__ "DMPlexGetAdjacency_Private"
415 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
416 {
417   const PetscInt *star  = tmpClosure;
418   PetscInt       numAdj = 0, maxAdjSize = *adjSize, starSize, s;
419   PetscErrorCode ierr;
420 
421   PetscFunctionBegin;
422   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt**) &star);CHKERRQ(ierr);
423   for (s = 2; s < starSize*2; s += 2) {
424     const PetscInt *closure = PETSC_NULL;
425     PetscInt       closureSize, c, q;
426 
427     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
428     for (c = 0; c < closureSize*2; c += 2) {
429       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
430         if (closure[c] == adj[q]) break;
431       }
432       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
433     }
434     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt**) &closure);CHKERRQ(ierr);
435   }
436   *adjSize = numAdj;
437   PetscFunctionReturn(0);
438 }
439 
440 #undef __FUNCT__
441 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
442 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
443 {
444   DM_Plex *mesh = (DM_Plex*) dm->data;
445 
446   PetscFunctionBegin;
447   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
448   mesh->preallocCenterDim = preallocCenterDim;
449   PetscFunctionReturn(0);
450 }
451 
452 #undef __FUNCT__
453 #define __FUNCT__ "DMPlexPreallocateOperator"
454 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
455 {
456   DM_Plex           *mesh = (DM_Plex*) dm->data;
457   MPI_Comm          comm  = ((PetscObject) dm)->comm;
458   PetscSF           sf, sfDof, sfAdj;
459   PetscSection      leafSectionAdj, rootSectionAdj, sectionAdj;
460   PetscInt          nleaves, l, p;
461   const PetscInt    *leaves;
462   const PetscSFNode *remotes;
463   PetscInt          dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
464   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
465   PetscInt          depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
466   PetscLayout       rLayout;
467   PetscInt          locRows, rStart, rEnd, r;
468   PetscMPIInt       size;
469   PetscBool         useClosure, debug = PETSC_FALSE;
470   PetscErrorCode    ierr;
471 
472   PetscFunctionBegin;
473   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
474   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
475   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
476   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
477   /* Create dof SF based on point SF */
478   if (debug) {
479     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
480     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
481     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
485   }
486   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
487   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
488   if (debug) {
489     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
490     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
491   }
492   /* Create section for dof adjacency (dof ==> # adj dof) */
493   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
494   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
495   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
496   if (mesh->preallocCenterDim == dim) {
497     useClosure = PETSC_FALSE;
498   } else if (mesh->preallocCenterDim == 0) {
499     useClosure = PETSC_TRUE;
500   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
501 
502   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
503   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
504   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
505   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
508   /*   Fill in the ghost dofs on the interface */
509   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
510   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
511   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
512 
513   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
514   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
515 
516   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
517 
518   /*
519    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
520     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
521        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
522     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
523        Create sfAdj connecting rootSectionAdj and leafSectionAdj
524     3. Visit unowned points on interface, write adjacencies to adj
525        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
526     4. Visit owned points on interface, write adjacencies to rootAdj
527        Remove redundancy in rootAdj
528    ** The last two traversals use transitive closure
529     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
530        Allocate memory addressed by sectionAdj (cols)
531     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
532    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
533   */
534 
535   for (l = 0; l < nleaves; ++l) {
536     PetscInt dof, off, d, q;
537     PetscInt p = leaves[l], numAdj = maxAdjSize;
538 
539     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
540     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
541     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
542     for (q = 0; q < numAdj; ++q) {
543       PetscInt ndof, ncdof;
544 
545       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
546       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
547       for (d = off; d < off+dof; ++d) {
548         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
549       }
550     }
551   }
552   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
553   if (debug) {
554     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
555     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
556   }
557   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
558   if (size > 1) {
559     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
560     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561   }
562   if (debug) {
563     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
564     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
565   }
566   /* Add in local adjacency sizes for owned dofs on interface (roots) */
567   for (p = pStart; p < pEnd; ++p) {
568     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
569 
570     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
571     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
572     if (!dof) continue;
573     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
574     if (adof <= 0) continue;
575     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
576     for (q = 0; q < numAdj; ++q) {
577       PetscInt ndof, ncdof;
578 
579       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
580       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
581       for (d = off; d < off+dof; ++d) {
582         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
583       }
584     }
585   }
586   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
587   if (debug) {
588     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
589     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
590   }
591   /* Create adj SF based on dof SF */
592   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
593   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
596     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
597   }
598   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
599   /* Create leaf adjacency */
600   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
601   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
602   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
603   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
604   for (l = 0; l < nleaves; ++l) {
605     PetscInt dof, off, d, q;
606     PetscInt p = leaves[l], numAdj = maxAdjSize;
607 
608     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
609     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
610     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
611     for (d = off; d < off+dof; ++d) {
612       PetscInt aoff, i = 0;
613 
614       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
615       for (q = 0; q < numAdj; ++q) {
616         PetscInt ndof, ncdof, ngoff, nd;
617 
618         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
619         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
620         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
621         for (nd = 0; nd < ndof-ncdof; ++nd) {
622           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
623           ++i;
624         }
625       }
626     }
627   }
628   /* Debugging */
629   if (debug) {
630     IS tmp;
631     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
632     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
633     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
634   }
635   /* Gather adjacenct indices to root */
636   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
637   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
638   for (r = 0; r < adjSize; ++r) rootAdj[r] = -1;
639   if (size > 1) {
640     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
641     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
642   }
643   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
644   ierr = PetscFree(adj);CHKERRQ(ierr);
645   /* Debugging */
646   if (debug) {
647     IS tmp;
648     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
649     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
650     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
651   }
652   /* Add in local adjacency indices for owned dofs on interface (roots) */
653   for (p = pStart; p < pEnd; ++p) {
654     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
655 
656     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
657     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
658     if (!dof) continue;
659     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
660     if (adof <= 0) continue;
661     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
662     for (d = off; d < off+dof; ++d) {
663       PetscInt adof, aoff, i;
664 
665       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
666       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
667       i    = adof-1;
668       for (q = 0; q < numAdj; ++q) {
669         PetscInt ndof, ncdof, ngoff, nd;
670 
671         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
672         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
673         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
674         for (nd = 0; nd < ndof-ncdof; ++nd) {
675           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
676           --i;
677         }
678       }
679     }
680   }
681   /* Debugging */
682   if (debug) {
683     IS tmp;
684     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
685     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
686     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
687   }
688   /* Compress indices */
689   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
690   for (p = pStart; p < pEnd; ++p) {
691     PetscInt dof, cdof, off, d;
692     PetscInt adof, aoff;
693 
694     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
695     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
696     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
697     if (!dof) continue;
698     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
699     if (adof <= 0) continue;
700     for (d = off; d < off+dof-cdof; ++d) {
701       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
702       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
703       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
704       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
705     }
706   }
707   /* Debugging */
708   if (debug) {
709     IS tmp;
710     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
711     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
712     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
713     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
714     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
715   }
716   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
717   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
718   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
719   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
720   for (p = pStart; p < pEnd; ++p) {
721     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
722     PetscBool found  = PETSC_TRUE;
723 
724     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
725     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
726     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
727     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
728     for (d = 0; d < dof-cdof; ++d) {
729       PetscInt ldof, rdof;
730 
731       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
732       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
733       if (ldof > 0) {
734         /* We do not own this point */
735       } else if (rdof > 0) {
736         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
737       } else {
738         found = PETSC_FALSE;
739       }
740     }
741     if (found) continue;
742     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
743     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
744     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
745     for (q = 0; q < numAdj; ++q) {
746       PetscInt ndof, ncdof, noff;
747 
748       /* Adjacent points may not be in the section chart */
749       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
750       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
751       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
752       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
753       for (d = goff; d < goff+dof-cdof; ++d) {
754         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
755       }
756     }
757   }
758   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
759   if (debug) {
760     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
761     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
762   }
763   /* Get adjacent indices */
764   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
765   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
766   for (p = pStart; p < pEnd; ++p) {
767     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
768     PetscBool found  = PETSC_TRUE;
769 
770     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
771     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
772     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
773     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
774     for (d = 0; d < dof-cdof; ++d) {
775       PetscInt ldof, rdof;
776 
777       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
778       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
779       if (ldof > 0) {
780         /* We do not own this point */
781       } else if (rdof > 0) {
782         PetscInt aoff, roff;
783 
784         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
785         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
786         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
787       } else {
788         found = PETSC_FALSE;
789       }
790     }
791     if (found) continue;
792     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
793     for (d = goff; d < goff+dof-cdof; ++d) {
794       PetscInt adof, aoff, i = 0;
795 
796       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
797       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
798       for (q = 0; q < numAdj; ++q) {
799         PetscInt        ndof, ncdof, ngoff, nd;
800         const PetscInt *ncind;
801 
802         /* Adjacent points may not be in the section chart */
803         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
804         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
805         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
806         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
807         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
808         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
809           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd : ngoff+nd;
810         }
811       }
812       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
813     }
814   }
815   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
816   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
817   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
818   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
819   /* Debugging */
820   if (debug) {
821     IS tmp;
822     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
823     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
824     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
825   }
826   /* Create allocation vectors from adjacency graph */
827   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
828   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
829   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
830   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
831   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
832   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
833   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
834   /* Only loop over blocks of rows */
835   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
836   for (r = rStart/bs; r < rEnd/bs; ++r) {
837     const PetscInt row = r*bs;
838     PetscInt       numCols, cStart, c;
839 
840     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
841     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
842     for (c = cStart; c < cStart+numCols; ++c) {
843       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
844         ++dnz[r-rStart];
845         if (cols[c] >= row) ++dnzu[r-rStart];
846       } else {
847         ++onz[r-rStart];
848         if (cols[c] >= row) ++onzu[r-rStart];
849       }
850     }
851   }
852   if (bs > 1) {
853     for (r = 0; r < locRows/bs; ++r) {
854       dnz[r]  /= bs;
855       onz[r]  /= bs;
856       dnzu[r] /= bs;
857       onzu[r] /= bs;
858     }
859   }
860   /* Set matrix pattern */
861   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
862   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
863   /* Fill matrix with zeros */
864   if (fillMatrix) {
865     PetscScalar *values;
866     PetscInt    maxRowLen = 0;
867 
868     for (r = rStart; r < rEnd; ++r) {
869       PetscInt len;
870 
871       ierr      = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
872       maxRowLen = PetscMax(maxRowLen, len);
873     }
874     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
875     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
876     for (r = rStart; r < rEnd; ++r) {
877       PetscInt numCols, cStart;
878 
879       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
880       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
881       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
882     }
883     ierr = PetscFree(values);CHKERRQ(ierr);
884     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
885     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
886   }
887   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
888   ierr = PetscFree(cols);CHKERRQ(ierr);
889   PetscFunctionReturn(0);
890 }
891 
892 #if 0
893 #undef __FUNCT__
894 #define __FUNCT__ "DMPlexPreallocateOperator_2"
895 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
896 {
897   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 
906   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
907 
908   ierr    = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910 
911   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
912   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
914   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
915   for (c=cStart; c<cEnd; c++) {
916     PetscInt *support = tmpClosure;
917     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
918     for (p=0; p<supportSize; p++) lvisits[support[p]]++;
919   }
920   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
921   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
923   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924 
925   ierr = PetscSFGetRanks();CHKERRQ(ierr);
926 
927 
928   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
929   for (c=cStart; c<cEnd; c++) {
930     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
931     /*
932      Depth-first walk of transitive closure.
933      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
934      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
935      */
936   }
937 
938   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
939   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
940   PetscFunctionReturn(0);
941 }
942 #endif
943 
944 #undef __FUNCT__
945 #define __FUNCT__ "DMCreateMatrix_Plex"
946 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
947 {
948   PetscSection   section, sectionGlobal;
949   PetscInt       bs = -1;
950   PetscInt       localSize;
951   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
952   PetscErrorCode ierr;
953 
954   PetscFunctionBegin;
955 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
956   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
957 #endif
958   if (!mtype) mtype = MATAIJ;
959   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
960   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
961   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
962   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
963   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
964   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
965   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
966   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
967   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
974   /* Check for symmetric storage */
975   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
976   if (isSymmetric) {
977     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
978   }
979   if (!isShell) {
980     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
981     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal, bsMax, bsMin;
982 
983     if (bs < 0) {
984       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
985         PetscInt pStart, pEnd, p, dof;
986 
987         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
988         for (p = pStart; p < pEnd; ++p) {
989           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
990           if (dof) {
991             if (bs < 0) {
992               bs = dof;
993             } else if (bs != dof) {
994               /* Layout does not admit a pointwise block size */
995               bs = 1;
996               break;
997             }
998           }
999         }
1000         /* Must have same blocksize on all procs (some might have no points) */
1001         bsLocal = bs;
1002         ierr = MPI_Allreduce(&bsLocal, &bsMax, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1003         bsLocal = bs < 0 ? bsMax : bs;
1004         ierr = MPI_Allreduce(&bsLocal, &bsMin, 1, MPIU_INT, MPI_MIN, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1005         if (bsMin != bsMax) {
1006           bs = 1;
1007         } else {
1008           bs = bsMax;
1009         }
1010       } else {
1011         bs = 1;
1012       }
1013     }
1014     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1015     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1016     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1017     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1018     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1019     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1020     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1021   }
1022   PetscFunctionReturn(0);
1023 }
1024 
1025 #undef __FUNCT__
1026 #define __FUNCT__ "DMPlexGetDimension"
1027 /*@
1028   DMPlexGetDimension - Return the topological mesh dimension
1029 
1030   Not collective
1031 
1032   Input Parameter:
1033 . mesh - The DMPlex
1034 
1035   Output Parameter:
1036 . dim - The topological mesh dimension
1037 
1038   Level: beginner
1039 
1040 .seealso: DMPlexCreate()
1041 @*/
1042 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1043 {
1044   DM_Plex *mesh = (DM_Plex*) dm->data;
1045 
1046   PetscFunctionBegin;
1047   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1048   PetscValidPointer(dim, 2);
1049   *dim = mesh->dim;
1050   PetscFunctionReturn(0);
1051 }
1052 
1053 #undef __FUNCT__
1054 #define __FUNCT__ "DMPlexSetDimension"
1055 /*@
1056   DMPlexSetDimension - Set the topological mesh dimension
1057 
1058   Collective on mesh
1059 
1060   Input Parameters:
1061 + mesh - The DMPlex
1062 - dim - The topological mesh dimension
1063 
1064   Level: beginner
1065 
1066 .seealso: DMPlexCreate()
1067 @*/
1068 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1069 {
1070   DM_Plex *mesh = (DM_Plex*) dm->data;
1071 
1072   PetscFunctionBegin;
1073   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1074   PetscValidLogicalCollectiveInt(dm, dim, 2);
1075   mesh->dim               = dim;
1076   mesh->preallocCenterDim = dim;
1077   PetscFunctionReturn(0);
1078 }
1079 
1080 #undef __FUNCT__
1081 #define __FUNCT__ "DMPlexGetChart"
1082 /*@
1083   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1084 
1085   Not collective
1086 
1087   Input Parameter:
1088 . mesh - The DMPlex
1089 
1090   Output Parameters:
1091 + pStart - The first mesh point
1092 - pEnd   - The upper bound for mesh points
1093 
1094   Level: beginner
1095 
1096 .seealso: DMPlexCreate(), DMPlexSetChart()
1097 @*/
1098 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1099 {
1100   DM_Plex        *mesh = (DM_Plex*) dm->data;
1101   PetscErrorCode ierr;
1102 
1103   PetscFunctionBegin;
1104   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1105   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1106   PetscFunctionReturn(0);
1107 }
1108 
1109 #undef __FUNCT__
1110 #define __FUNCT__ "DMPlexSetChart"
1111 /*@
1112   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1113 
1114   Not collective
1115 
1116   Input Parameters:
1117 + mesh - The DMPlex
1118 . pStart - The first mesh point
1119 - pEnd   - The upper bound for mesh points
1120 
1121   Output Parameters:
1122 
1123   Level: beginner
1124 
1125 .seealso: DMPlexCreate(), DMPlexGetChart()
1126 @*/
1127 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1128 {
1129   DM_Plex        *mesh = (DM_Plex*) dm->data;
1130   PetscErrorCode ierr;
1131 
1132   PetscFunctionBegin;
1133   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1134   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1135   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1136   PetscFunctionReturn(0);
1137 }
1138 
1139 #undef __FUNCT__
1140 #define __FUNCT__ "DMPlexGetConeSize"
1141 /*@
1142   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1143 
1144   Not collective
1145 
1146   Input Parameters:
1147 + mesh - The DMPlex
1148 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1149 
1150   Output Parameter:
1151 . size - The cone size for point p
1152 
1153   Level: beginner
1154 
1155 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1156 @*/
1157 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1158 {
1159   DM_Plex        *mesh = (DM_Plex*) dm->data;
1160   PetscErrorCode ierr;
1161 
1162   PetscFunctionBegin;
1163   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1164   PetscValidPointer(size, 3);
1165   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1166   PetscFunctionReturn(0);
1167 }
1168 
1169 #undef __FUNCT__
1170 #define __FUNCT__ "DMPlexSetConeSize"
1171 /*@
1172   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1173 
1174   Not collective
1175 
1176   Input Parameters:
1177 + mesh - The DMPlex
1178 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1179 - size - The cone size for point p
1180 
1181   Output Parameter:
1182 
1183   Note:
1184   This should be called after DMPlexSetChart().
1185 
1186   Level: beginner
1187 
1188 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1189 @*/
1190 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1191 {
1192   DM_Plex        *mesh = (DM_Plex*) dm->data;
1193   PetscErrorCode ierr;
1194 
1195   PetscFunctionBegin;
1196   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1197   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1198 
1199   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1200   PetscFunctionReturn(0);
1201 }
1202 
1203 #undef __FUNCT__
1204 #define __FUNCT__ "DMPlexGetCone"
1205 /*@C
1206   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1207 
1208   Not collective
1209 
1210   Input Parameters:
1211 + mesh - The DMPlex
1212 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1213 
1214   Output Parameter:
1215 . cone - An array of points which are on the in-edges for point p
1216 
1217   Level: beginner
1218 
1219   Note:
1220   This routine is not available in Fortran.
1221 
1222 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1223 @*/
1224 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1225 {
1226   DM_Plex        *mesh = (DM_Plex*) dm->data;
1227   PetscInt       off;
1228   PetscErrorCode ierr;
1229 
1230   PetscFunctionBegin;
1231   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1232   PetscValidPointer(cone, 3);
1233   ierr  = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1234   *cone = &mesh->cones[off];
1235   PetscFunctionReturn(0);
1236 }
1237 
1238 #undef __FUNCT__
1239 #define __FUNCT__ "DMPlexSetCone"
1240 /*@
1241   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1242 
1243   Not collective
1244 
1245   Input Parameters:
1246 + mesh - The DMPlex
1247 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1248 - cone - An array of points which are on the in-edges for point p
1249 
1250   Output Parameter:
1251 
1252   Note:
1253   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1254 
1255   Level: beginner
1256 
1257 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1258 @*/
1259 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1260 {
1261   DM_Plex        *mesh = (DM_Plex*) dm->data;
1262   PetscInt       pStart, pEnd;
1263   PetscInt       dof, off, c;
1264   PetscErrorCode ierr;
1265 
1266   PetscFunctionBegin;
1267   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1268   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1269   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1270   if (dof) PetscValidPointer(cone, 3);
1271   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1272   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);
1273   for (c = 0; c < dof; ++c) {
1274     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);
1275     mesh->cones[off+c] = cone[c];
1276   }
1277   PetscFunctionReturn(0);
1278 }
1279 
1280 #undef __FUNCT__
1281 #define __FUNCT__ "DMPlexGetConeOrientation"
1282 /*@C
1283   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1284 
1285   Not collective
1286 
1287   Input Parameters:
1288 + mesh - The DMPlex
1289 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1290 
1291   Output Parameter:
1292 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1293                     integer giving the prescription for cone traversal. If it is negative, the cone is
1294                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1295                     the index of the cone point on which to start.
1296 
1297   Level: beginner
1298 
1299   Note:
1300   This routine is not available in Fortran.
1301 
1302 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1303 @*/
1304 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1305 {
1306   DM_Plex        *mesh = (DM_Plex*) dm->data;
1307   PetscInt       off;
1308   PetscErrorCode ierr;
1309 
1310   PetscFunctionBegin;
1311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1312 #if defined(PETSC_USE_DEBUG)
1313   {
1314     PetscInt dof;
1315     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1316     if (dof) PetscValidPointer(coneOrientation, 3);
1317   }
1318 #endif
1319   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1320 
1321   *coneOrientation = &mesh->coneOrientations[off];
1322   PetscFunctionReturn(0);
1323 }
1324 
1325 #undef __FUNCT__
1326 #define __FUNCT__ "DMPlexSetConeOrientation"
1327 /*@
1328   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1329 
1330   Not collective
1331 
1332   Input Parameters:
1333 + mesh - The DMPlex
1334 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1335 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1336                     integer giving the prescription for cone traversal. If it is negative, the cone is
1337                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1338                     the index of the cone point on which to start.
1339 
1340   Output Parameter:
1341 
1342   Note:
1343   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1344 
1345   Level: beginner
1346 
1347 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1348 @*/
1349 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1350 {
1351   DM_Plex        *mesh = (DM_Plex*) dm->data;
1352   PetscInt       pStart, pEnd;
1353   PetscInt       dof, off, c;
1354   PetscErrorCode ierr;
1355 
1356   PetscFunctionBegin;
1357   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1358   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1359   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1360   if (dof) PetscValidPointer(coneOrientation, 3);
1361   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1362   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);
1363   for (c = 0; c < dof; ++c) {
1364     PetscInt cdof, o = coneOrientation[c];
1365 
1366     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1367     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);
1368     mesh->coneOrientations[off+c] = o;
1369   }
1370   PetscFunctionReturn(0);
1371 }
1372 
1373 #undef __FUNCT__
1374 #define __FUNCT__ "DMPlexInsertCone"
1375 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1376 {
1377   DM_Plex        *mesh = (DM_Plex*) dm->data;
1378   PetscInt       pStart, pEnd;
1379   PetscInt       dof, off;
1380   PetscErrorCode ierr;
1381 
1382   PetscFunctionBegin;
1383   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1384   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1385   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1386   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1387   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);
1388   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);
1389   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);
1390   mesh->cones[off+conePos] = conePoint;
1391   PetscFunctionReturn(0);
1392 }
1393 
1394 #undef __FUNCT__
1395 #define __FUNCT__ "DMPlexGetSupportSize"
1396 /*@
1397   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1398 
1399   Not collective
1400 
1401   Input Parameters:
1402 + mesh - The DMPlex
1403 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1404 
1405   Output Parameter:
1406 . size - The support size for point p
1407 
1408   Level: beginner
1409 
1410 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1411 @*/
1412 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1413 {
1414   DM_Plex        *mesh = (DM_Plex*) dm->data;
1415   PetscErrorCode ierr;
1416 
1417   PetscFunctionBegin;
1418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1419   PetscValidPointer(size, 3);
1420   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1421   PetscFunctionReturn(0);
1422 }
1423 
1424 #undef __FUNCT__
1425 #define __FUNCT__ "DMPlexSetSupportSize"
1426 /*@
1427   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1428 
1429   Not collective
1430 
1431   Input Parameters:
1432 + mesh - The DMPlex
1433 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1434 - size - The support size for point p
1435 
1436   Output Parameter:
1437 
1438   Note:
1439   This should be called after DMPlexSetChart().
1440 
1441   Level: beginner
1442 
1443 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1444 @*/
1445 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1446 {
1447   DM_Plex        *mesh = (DM_Plex*) dm->data;
1448   PetscErrorCode ierr;
1449 
1450   PetscFunctionBegin;
1451   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1452   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1453 
1454   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1455   PetscFunctionReturn(0);
1456 }
1457 
1458 #undef __FUNCT__
1459 #define __FUNCT__ "DMPlexGetSupport"
1460 /*@C
1461   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1462 
1463   Not collective
1464 
1465   Input Parameters:
1466 + mesh - The DMPlex
1467 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1468 
1469   Output Parameter:
1470 . support - An array of points which are on the out-edges for point p
1471 
1472   Level: beginner
1473 
1474 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1475 @*/
1476 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1477 {
1478   DM_Plex        *mesh = (DM_Plex*) dm->data;
1479   PetscInt       off;
1480   PetscErrorCode ierr;
1481 
1482   PetscFunctionBegin;
1483   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1484   PetscValidPointer(support, 3);
1485   ierr     = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1486   *support = &mesh->supports[off];
1487   PetscFunctionReturn(0);
1488 }
1489 
1490 #undef __FUNCT__
1491 #define __FUNCT__ "DMPlexSetSupport"
1492 /*@
1493   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1494 
1495   Not collective
1496 
1497   Input Parameters:
1498 + mesh - The DMPlex
1499 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1500 - support - An array of points which are on the in-edges for point p
1501 
1502   Output Parameter:
1503 
1504   Note:
1505   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1506 
1507   Level: beginner
1508 
1509 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1510 @*/
1511 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1512 {
1513   DM_Plex        *mesh = (DM_Plex*) dm->data;
1514   PetscInt       pStart, pEnd;
1515   PetscInt       dof, off, c;
1516   PetscErrorCode ierr;
1517 
1518   PetscFunctionBegin;
1519   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1520   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1521   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1522   if (dof) PetscValidPointer(support, 3);
1523   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1524   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);
1525   for (c = 0; c < dof; ++c) {
1526     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);
1527     mesh->supports[off+c] = support[c];
1528   }
1529   PetscFunctionReturn(0);
1530 }
1531 
1532 #undef __FUNCT__
1533 #define __FUNCT__ "DMPlexInsertSupport"
1534 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1535 {
1536   DM_Plex        *mesh = (DM_Plex*) dm->data;
1537   PetscInt       pStart, pEnd;
1538   PetscInt       dof, off;
1539   PetscErrorCode ierr;
1540 
1541   PetscFunctionBegin;
1542   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1543   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1544   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1545   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1546   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);
1547   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);
1548   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);
1549   mesh->supports[off+supportPos] = supportPoint;
1550   PetscFunctionReturn(0);
1551 }
1552 
1553 #undef __FUNCT__
1554 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1555 /*@C
1556   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1557 
1558   Not collective
1559 
1560   Input Parameters:
1561 + mesh - The DMPlex
1562 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1563 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1564 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1565 
1566   Output Parameters:
1567 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1568 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1569 
1570   Note:
1571   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1572 
1573   Level: beginner
1574 
1575 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1576 @*/
1577 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1578 {
1579   DM_Plex        *mesh = (DM_Plex*) dm->data;
1580   PetscInt       *closure, *fifo;
1581   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1582   PetscInt       tmpSize, t;
1583   PetscInt       depth       = 0, maxSize;
1584   PetscInt       closureSize = 2, fifoSize = 0, fifoStart = 0;
1585   PetscErrorCode ierr;
1586 
1587   PetscFunctionBegin;
1588   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1589   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1590   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1591   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1592   if (*points) {
1593     closure = *points;
1594   } else {
1595     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1596   }
1597   closure[0] = p; closure[1] = 0;
1598   /* This is only 1-level */
1599   if (useCone) {
1600     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1601     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1602     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1603   } else {
1604     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1605     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1606   }
1607   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1608     const PetscInt cp = tmp[t];
1609     const PetscInt co = tmpO ? tmpO[t] : 0;
1610 
1611     closure[closureSize]   = cp;
1612     closure[closureSize+1] = co;
1613     fifo[fifoSize]         = cp;
1614     fifo[fifoSize+1]       = co;
1615   }
1616   while (fifoSize - fifoStart) {
1617     const PetscInt q   = fifo[fifoStart];
1618     const PetscInt o   = fifo[fifoStart+1];
1619     const PetscInt rev = o >= 0 ? 0 : 1;
1620     const PetscInt off = rev ? -(o+1) : o;
1621 
1622     if (useCone) {
1623       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1624       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1625       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1626     } else {
1627       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1628       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1629       tmpO = PETSC_NULL;
1630     }
1631     for (t = 0; t < tmpSize; ++t) {
1632       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1633       const PetscInt cp = tmp[i];
1634       /* Must propogate orientation */
1635       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1636       PetscInt       c;
1637 
1638       /* Check for duplicate */
1639       for (c = 0; c < closureSize; c += 2) {
1640         if (closure[c] == cp) break;
1641       }
1642       if (c == closureSize) {
1643         closure[closureSize]   = cp;
1644         closure[closureSize+1] = co;
1645         fifo[fifoSize]         = cp;
1646         fifo[fifoSize+1]       = co;
1647         closureSize           += 2;
1648         fifoSize              += 2;
1649       }
1650     }
1651     fifoStart += 2;
1652   }
1653   if (numPoints) *numPoints = closureSize/2;
1654   if (points)    *points    = closure;
1655   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1656   PetscFunctionReturn(0);
1657 }
1658 
1659 #undef __FUNCT__
1660 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1661 /*@C
1662   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1663 
1664   Not collective
1665 
1666   Input Parameters:
1667 + mesh - The DMPlex
1668 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1669 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1670 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1671 
1672   Output Parameters:
1673 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1674 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1675 
1676   Note:
1677   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1678 
1679   Level: beginner
1680 
1681 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1682 @*/
1683 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1684 {
1685   PetscErrorCode ierr;
1686 
1687   PetscFunctionBegin;
1688   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1689   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1690   PetscFunctionReturn(0);
1691 }
1692 
1693 #undef __FUNCT__
1694 #define __FUNCT__ "DMPlexGetFaces"
1695 /*
1696   DMPlexGetFaces -
1697 
1698   Note: This will only work for cell-vertex meshes.
1699 */
1700 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1701 {
1702   DM_Plex        *mesh = (DM_Plex*) dm->data;
1703   const PetscInt *cone = PETSC_NULL;
1704   PetscInt       depth = 0, dim, coneSize;
1705   PetscErrorCode ierr;
1706 
1707   PetscFunctionBegin;
1708   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1709   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1710   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1711   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1712   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1713   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1714   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1715   switch (dim) {
1716   case 2:
1717     switch (coneSize) {
1718     case 3:
1719       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1720       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1721       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1722       *numFaces         = 3;
1723       *faceSize         = 2;
1724       *faces            = mesh->facesTmp;
1725       break;
1726     case 4:
1727       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1728       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1729       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1730       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1731       *numFaces         = 4;
1732       *faceSize         = 2;
1733       *faces            = mesh->facesTmp;
1734       break;
1735     default:
1736       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1737     }
1738     break;
1739   case 3:
1740     switch (coneSize) {
1741     case 3:
1742       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1743       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1744       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1745       *numFaces         = 3;
1746       *faceSize         = 2;
1747       *faces            = mesh->facesTmp;
1748       break;
1749     case 4:
1750       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1751       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1752       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1753       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1754       *numFaces         = 4;
1755       *faceSize         = 3;
1756       *faces            = mesh->facesTmp;
1757       break;
1758     default:
1759       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1760     }
1761     break;
1762   default:
1763     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1764   }
1765   PetscFunctionReturn(0);
1766 }
1767 
1768 #undef __FUNCT__
1769 #define __FUNCT__ "DMPlexGetMaxSizes"
1770 /*@
1771   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1772 
1773   Not collective
1774 
1775   Input Parameter:
1776 . mesh - The DMPlex
1777 
1778   Output Parameters:
1779 + maxConeSize - The maximum number of in-edges
1780 - maxSupportSize - The maximum number of out-edges
1781 
1782   Level: beginner
1783 
1784 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1785 @*/
1786 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1787 {
1788   DM_Plex *mesh = (DM_Plex*) dm->data;
1789 
1790   PetscFunctionBegin;
1791   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1792   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1793   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1794   PetscFunctionReturn(0);
1795 }
1796 
1797 #undef __FUNCT__
1798 #define __FUNCT__ "DMSetUp_Plex"
1799 PetscErrorCode DMSetUp_Plex(DM dm)
1800 {
1801   DM_Plex        *mesh = (DM_Plex*) dm->data;
1802   PetscInt       size;
1803   PetscErrorCode ierr;
1804 
1805   PetscFunctionBegin;
1806   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1807   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1808   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1809   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1810   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1811   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1812   if (mesh->maxSupportSize) {
1813     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1814     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1815     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1816   }
1817   PetscFunctionReturn(0);
1818 }
1819 
1820 #undef __FUNCT__
1821 #define __FUNCT__ "DMCreateSubDM_Plex"
1822 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1823 {
1824   PetscSection   section, sectionGlobal;
1825   PetscInt       *subIndices;
1826   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1827   PetscErrorCode ierr;
1828 
1829   PetscFunctionBegin;
1830   if (!numFields) PetscFunctionReturn(0);
1831   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1832   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1833   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1834   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1835   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1836   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);
1837   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1838   for (p = pStart; p < pEnd; ++p) {
1839     PetscInt gdof;
1840 
1841     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1842     if (gdof > 0) {
1843       for (f = 0; f < numFields; ++f) {
1844         PetscInt fdof, fcdof;
1845 
1846         ierr     = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1847         ierr     = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1848         subSize += fdof-fcdof;
1849       }
1850     }
1851   }
1852   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1853   for (p = pStart; p < pEnd; ++p) {
1854     PetscInt gdof, goff;
1855 
1856     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1857     if (gdof > 0) {
1858       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1859       for (f = 0; f < numFields; ++f) {
1860         PetscInt fdof, fcdof, fc, f2, poff = 0;
1861 
1862         /* Can get rid of this loop by storing field information in the global section */
1863         for (f2 = 0; f2 < fields[f]; ++f2) {
1864           ierr  = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1865           ierr  = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1866           poff += fdof-fcdof;
1867         }
1868         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1869         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1870         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1871           subIndices[subOff] = goff+poff+fc;
1872         }
1873       }
1874     }
1875   }
1876   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1877   if (subdm) {
1878     PetscSection subsection;
1879     PetscBool    haveNull = PETSC_FALSE;
1880     PetscInt     f, nf = 0;
1881 
1882     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1883     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1884     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1885     for (f = 0; f < numFields; ++f) {
1886       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1887       if ((*subdm)->nullspaceConstructors[f]) {
1888         haveNull = PETSC_TRUE;
1889         nf       = f;
1890       }
1891     }
1892     if (haveNull) {
1893       MatNullSpace nullSpace;
1894 
1895       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1896       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1897       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1898     }
1899     if (dm->fields) {
1900       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);
1901       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1902       for (f = 0; f < numFields; ++f) {
1903         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1904       }
1905       if (numFields == 1) {
1906         MatNullSpace space;
1907         Mat          pmat;
1908 
1909         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject*) &space);CHKERRQ(ierr);
1910         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1911         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject*) &space);CHKERRQ(ierr);
1912         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1913         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject*) &pmat);CHKERRQ(ierr);
1914         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1915       }
1916     }
1917   }
1918   PetscFunctionReturn(0);
1919 }
1920 
1921 #undef __FUNCT__
1922 #define __FUNCT__ "DMPlexSymmetrize"
1923 /*@
1924   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1925 
1926   Not collective
1927 
1928   Input Parameter:
1929 . mesh - The DMPlex
1930 
1931   Output Parameter:
1932 
1933   Note:
1934   This should be called after all calls to DMPlexSetCone()
1935 
1936   Level: beginner
1937 
1938 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1939 @*/
1940 PetscErrorCode DMPlexSymmetrize(DM dm)
1941 {
1942   DM_Plex        *mesh = (DM_Plex*) dm->data;
1943   PetscInt       *offsets;
1944   PetscInt       supportSize;
1945   PetscInt       pStart, pEnd, p;
1946   PetscErrorCode ierr;
1947 
1948   PetscFunctionBegin;
1949   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1950   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1951   /* Calculate support sizes */
1952   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1953   for (p = pStart; p < pEnd; ++p) {
1954     PetscInt dof, off, c;
1955 
1956     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1957     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1958     for (c = off; c < off+dof; ++c) {
1959       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1960     }
1961   }
1962   for (p = pStart; p < pEnd; ++p) {
1963     PetscInt dof;
1964 
1965     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1966 
1967     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1968   }
1969   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1970   /* Calculate supports */
1971   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1972   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1973   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1974   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1975   for (p = pStart; p < pEnd; ++p) {
1976     PetscInt dof, off, c;
1977 
1978     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1979     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1980     for (c = off; c < off+dof; ++c) {
1981       const PetscInt q = mesh->cones[c];
1982       PetscInt       offS;
1983 
1984       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1985 
1986       mesh->supports[offS+offsets[q]] = p;
1987       ++offsets[q];
1988     }
1989   }
1990   ierr = PetscFree(offsets);CHKERRQ(ierr);
1991   PetscFunctionReturn(0);
1992 }
1993 
1994 #undef __FUNCT__
1995 #define __FUNCT__ "DMPlexSetDepth_Private"
1996 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1997 {
1998   PetscInt       d;
1999   PetscErrorCode ierr;
2000 
2001   PetscFunctionBegin;
2002   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
2003   if (d < 0) {
2004     /* We are guaranteed that the point has a cone since the depth was not yet set */
2005     const PetscInt *cone = PETSC_NULL;
2006     PetscInt       dCone;
2007 
2008     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2009     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2010     d    = dCone+1;
2011     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2012   }
2013   *depth = d;
2014   PetscFunctionReturn(0);
2015 }
2016 
2017 #undef __FUNCT__
2018 #define __FUNCT__ "DMPlexStratify"
2019 /*@
2020   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2021   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2022   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2023   the DAG.
2024 
2025   Not collective
2026 
2027   Input Parameter:
2028 . mesh - The DMPlex
2029 
2030   Output Parameter:
2031 
2032   Notes:
2033   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2034   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2035 
2036   This should be called after all calls to DMPlexSymmetrize()
2037 
2038   Level: beginner
2039 
2040 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2041 @*/
2042 PetscErrorCode DMPlexStratify(DM dm)
2043 {
2044   DM_Plex        *mesh = (DM_Plex*) dm->data;
2045   PetscInt       pStart, pEnd, p;
2046   PetscInt       numRoots = 0, numLeaves = 0;
2047   PetscErrorCode ierr;
2048 
2049   PetscFunctionBegin;
2050   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2051   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2052   /* Calculate depth */
2053   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2054   /* Initialize roots and count leaves */
2055   for (p = pStart; p < pEnd; ++p) {
2056     PetscInt coneSize, supportSize;
2057 
2058     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2059     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2060     if (!coneSize && supportSize) {
2061       ++numRoots;
2062       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2063     } else if (!supportSize && coneSize) {
2064       ++numLeaves;
2065     } else if (!supportSize && !coneSize) {
2066       /* Isolated points */
2067       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2068     }
2069   }
2070   if (numRoots + numLeaves == (pEnd - pStart)) {
2071     for (p = pStart; p < pEnd; ++p) {
2072       PetscInt coneSize, supportSize;
2073 
2074       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2075       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2076       if (!supportSize && coneSize) {
2077         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2078       }
2079     }
2080   } else {
2081     /* This might be slow since lookup is not fast */
2082     for (p = pStart; p < pEnd; ++p) {
2083       PetscInt depth;
2084 
2085       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2086     }
2087   }
2088   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2089   PetscFunctionReturn(0);
2090 }
2091 
2092 #undef __FUNCT__
2093 #define __FUNCT__ "DMPlexGetJoin"
2094 /*@C
2095   DMPlexGetJoin - Get an array for the join of the set of points
2096 
2097   Not Collective
2098 
2099   Input Parameters:
2100 + dm - The DMPlex object
2101 . numPoints - The number of input points for the join
2102 - points - The input points
2103 
2104   Output Parameters:
2105 + numCoveredPoints - The number of points in the join
2106 - coveredPoints - The points in the join
2107 
2108   Level: intermediate
2109 
2110   Note: Currently, this is restricted to a single level join
2111 
2112 .keywords: mesh
2113 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2114 @*/
2115 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2116 {
2117   DM_Plex        *mesh = (DM_Plex*) dm->data;
2118   PetscInt       *join[2];
2119   PetscInt       joinSize, i = 0;
2120   PetscInt       dof, off, p, c, m;
2121   PetscErrorCode ierr;
2122 
2123   PetscFunctionBegin;
2124   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2125   PetscValidPointer(points, 2);
2126   PetscValidPointer(numCoveredPoints, 3);
2127   PetscValidPointer(coveredPoints, 4);
2128   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2129   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2130   /* Copy in support of first point */
2131   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2132   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2133   for (joinSize = 0; joinSize < dof; ++joinSize) {
2134     join[i][joinSize] = mesh->supports[off+joinSize];
2135   }
2136   /* Check each successive support */
2137   for (p = 1; p < numPoints; ++p) {
2138     PetscInt newJoinSize = 0;
2139 
2140     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2141     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2142     for (c = 0; c < dof; ++c) {
2143       const PetscInt point = mesh->supports[off+c];
2144 
2145       for (m = 0; m < joinSize; ++m) {
2146         if (point == join[i][m]) {
2147           join[1-i][newJoinSize++] = point;
2148           break;
2149         }
2150       }
2151     }
2152     joinSize = newJoinSize;
2153     i        = 1-i;
2154   }
2155   *numCoveredPoints = joinSize;
2156   *coveredPoints    = join[i];
2157   ierr              = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2158   PetscFunctionReturn(0);
2159 }
2160 
2161 #undef __FUNCT__
2162 #define __FUNCT__ "DMPlexRestoreJoin"
2163 /*@C
2164   DMPlexRestoreJoin - Restore an array for the join of the set of points
2165 
2166   Not Collective
2167 
2168   Input Parameters:
2169 + dm - The DMPlex object
2170 . numPoints - The number of input points for the join
2171 - points - The input points
2172 
2173   Output Parameters:
2174 + numCoveredPoints - The number of points in the join
2175 - coveredPoints - The points in the join
2176 
2177   Level: intermediate
2178 
2179 .keywords: mesh
2180 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2181 @*/
2182 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2183 {
2184   PetscErrorCode ierr;
2185 
2186   PetscFunctionBegin;
2187   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2188   PetscValidPointer(coveredPoints, 4);
2189   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2190   PetscFunctionReturn(0);
2191 }
2192 
2193 #undef __FUNCT__
2194 #define __FUNCT__ "DMPlexGetFullJoin"
2195 /*@C
2196   DMPlexGetFullJoin - Get an array for the join of the set of points
2197 
2198   Not Collective
2199 
2200   Input Parameters:
2201 + dm - The DMPlex object
2202 . numPoints - The number of input points for the join
2203 - points - The input points
2204 
2205   Output Parameters:
2206 + numCoveredPoints - The number of points in the join
2207 - coveredPoints - The points in the join
2208 
2209   Level: intermediate
2210 
2211 .keywords: mesh
2212 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2213 @*/
2214 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2215 {
2216   DM_Plex        *mesh = (DM_Plex*) dm->data;
2217   PetscInt       *offsets, **closures;
2218   PetscInt       *join[2];
2219   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2220   PetscInt       p, d, c, m;
2221   PetscErrorCode ierr;
2222 
2223   PetscFunctionBegin;
2224   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2225   PetscValidPointer(points, 2);
2226   PetscValidPointer(numCoveredPoints, 3);
2227   PetscValidPointer(coveredPoints, 4);
2228 
2229   ierr    = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2230   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2231   ierr    = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2232   ierr    = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2233   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2234   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2235   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2236 
2237   for (p = 0; p < numPoints; ++p) {
2238     PetscInt closureSize;
2239 
2240     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2241 
2242     offsets[p*(depth+2)+0] = 0;
2243     for (d = 0; d < depth+1; ++d) {
2244       PetscInt pStart, pEnd, i;
2245 
2246       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2247       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2248         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2249           offsets[p*(depth+2)+d+1] = i;
2250           break;
2251         }
2252       }
2253       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2254     }
2255     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);
2256   }
2257   for (d = 0; d < depth+1; ++d) {
2258     PetscInt dof;
2259 
2260     /* Copy in support of first point */
2261     dof = offsets[d+1] - offsets[d];
2262     for (joinSize = 0; joinSize < dof; ++joinSize) {
2263       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2264     }
2265     /* Check each successive cone */
2266     for (p = 1; p < numPoints && joinSize; ++p) {
2267       PetscInt newJoinSize = 0;
2268 
2269       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2270       for (c = 0; c < dof; ++c) {
2271         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2272 
2273         for (m = 0; m < joinSize; ++m) {
2274           if (point == join[i][m]) {
2275             join[1-i][newJoinSize++] = point;
2276             break;
2277           }
2278         }
2279       }
2280       joinSize = newJoinSize;
2281       i        = 1-i;
2282     }
2283     if (joinSize) break;
2284   }
2285   *numCoveredPoints = joinSize;
2286   *coveredPoints    = join[i];
2287   for (p = 0; p < numPoints; ++p) {
2288     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2289   }
2290   ierr = PetscFree(closures);CHKERRQ(ierr);
2291   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2292   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2293   PetscFunctionReturn(0);
2294 }
2295 
2296 #undef __FUNCT__
2297 #define __FUNCT__ "DMPlexGetMeet"
2298 /*@C
2299   DMPlexGetMeet - Get an array for the meet of the set of points
2300 
2301   Not Collective
2302 
2303   Input Parameters:
2304 + dm - The DMPlex object
2305 . numPoints - The number of input points for the meet
2306 - points - The input points
2307 
2308   Output Parameters:
2309 + numCoveredPoints - The number of points in the meet
2310 - coveredPoints - The points in the meet
2311 
2312   Level: intermediate
2313 
2314   Note: Currently, this is restricted to a single level meet
2315 
2316 .keywords: mesh
2317 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2318 @*/
2319 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2320 {
2321   DM_Plex        *mesh = (DM_Plex*) dm->data;
2322   PetscInt       *meet[2];
2323   PetscInt       meetSize, i = 0;
2324   PetscInt       dof, off, p, c, m;
2325   PetscErrorCode ierr;
2326 
2327   PetscFunctionBegin;
2328   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2329   PetscValidPointer(points, 2);
2330   PetscValidPointer(numCoveringPoints, 3);
2331   PetscValidPointer(coveringPoints, 4);
2332   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2333   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2334   /* Copy in cone of first point */
2335   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2336   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2337   for (meetSize = 0; meetSize < dof; ++meetSize) {
2338     meet[i][meetSize] = mesh->cones[off+meetSize];
2339   }
2340   /* Check each successive cone */
2341   for (p = 1; p < numPoints; ++p) {
2342     PetscInt newMeetSize = 0;
2343 
2344     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2345     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2346     for (c = 0; c < dof; ++c) {
2347       const PetscInt point = mesh->cones[off+c];
2348 
2349       for (m = 0; m < meetSize; ++m) {
2350         if (point == meet[i][m]) {
2351           meet[1-i][newMeetSize++] = point;
2352           break;
2353         }
2354       }
2355     }
2356     meetSize = newMeetSize;
2357     i        = 1-i;
2358   }
2359   *numCoveringPoints = meetSize;
2360   *coveringPoints    = meet[i];
2361   ierr               = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2362   PetscFunctionReturn(0);
2363 }
2364 
2365 #undef __FUNCT__
2366 #define __FUNCT__ "DMPlexRestoreMeet"
2367 /*@C
2368   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2369 
2370   Not Collective
2371 
2372   Input Parameters:
2373 + dm - The DMPlex object
2374 . numPoints - The number of input points for the meet
2375 - points - The input points
2376 
2377   Output Parameters:
2378 + numCoveredPoints - The number of points in the meet
2379 - coveredPoints - The points in the meet
2380 
2381   Level: intermediate
2382 
2383 .keywords: mesh
2384 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2385 @*/
2386 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2387 {
2388   PetscErrorCode ierr;
2389 
2390   PetscFunctionBegin;
2391   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2392   PetscValidPointer(coveredPoints, 4);
2393   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void*) coveredPoints);CHKERRQ(ierr);
2394   PetscFunctionReturn(0);
2395 }
2396 
2397 #undef __FUNCT__
2398 #define __FUNCT__ "DMPlexGetFullMeet"
2399 /*@C
2400   DMPlexGetFullMeet - Get an array for the meet of the set of points
2401 
2402   Not Collective
2403 
2404   Input Parameters:
2405 + dm - The DMPlex object
2406 . numPoints - The number of input points for the meet
2407 - points - The input points
2408 
2409   Output Parameters:
2410 + numCoveredPoints - The number of points in the meet
2411 - coveredPoints - The points in the meet
2412 
2413   Level: intermediate
2414 
2415 .keywords: mesh
2416 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2417 @*/
2418 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2419 {
2420   DM_Plex        *mesh = (DM_Plex*) dm->data;
2421   PetscInt       *offsets, **closures;
2422   PetscInt       *meet[2];
2423   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2424   PetscInt       p, h, c, m;
2425   PetscErrorCode ierr;
2426 
2427   PetscFunctionBegin;
2428   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2429   PetscValidPointer(points, 2);
2430   PetscValidPointer(numCoveredPoints, 3);
2431   PetscValidPointer(coveredPoints, 4);
2432 
2433   ierr    = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2434   ierr    = PetscMalloc(numPoints * sizeof(PetscInt*), &closures);CHKERRQ(ierr);
2435   ierr    = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2436   maxSize = PetscPowInt(mesh->maxConeSize,height);
2437   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2438   ierr    = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2439 
2440   for (p = 0; p < numPoints; ++p) {
2441     PetscInt closureSize;
2442 
2443     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2444 
2445     offsets[p*(height+2)+0] = 0;
2446     for (h = 0; h < height+1; ++h) {
2447       PetscInt pStart, pEnd, i;
2448 
2449       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2450       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2451         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2452           offsets[p*(height+2)+h+1] = i;
2453           break;
2454         }
2455       }
2456       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2457     }
2458     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);
2459   }
2460   for (h = 0; h < height+1; ++h) {
2461     PetscInt dof;
2462 
2463     /* Copy in cone of first point */
2464     dof = offsets[h+1] - offsets[h];
2465     for (meetSize = 0; meetSize < dof; ++meetSize) {
2466       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2467     }
2468     /* Check each successive cone */
2469     for (p = 1; p < numPoints && meetSize; ++p) {
2470       PetscInt newMeetSize = 0;
2471 
2472       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2473       for (c = 0; c < dof; ++c) {
2474         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2475 
2476         for (m = 0; m < meetSize; ++m) {
2477           if (point == meet[i][m]) {
2478             meet[1-i][newMeetSize++] = point;
2479             break;
2480           }
2481         }
2482       }
2483       meetSize = newMeetSize;
2484       i        = 1-i;
2485     }
2486     if (meetSize) break;
2487   }
2488   *numCoveredPoints = meetSize;
2489   *coveredPoints    = meet[i];
2490   for (p = 0; p < numPoints; ++p) {
2491     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2492   }
2493   ierr = PetscFree(closures);CHKERRQ(ierr);
2494   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2495   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2496   PetscFunctionReturn(0);
2497 }
2498 
2499 #undef __FUNCT__
2500 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2501 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2502 {
2503   MPI_Comm       comm = ((PetscObject) dm)->comm;
2504   PetscInt       cellDim;
2505   PetscErrorCode ierr;
2506 
2507   PetscFunctionBegin;
2508   PetscValidPointer(numFaceVertices,3);
2509   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2510   switch (cellDim) {
2511   case 0:
2512     *numFaceVertices = 0;
2513     break;
2514   case 1:
2515     *numFaceVertices = 1;
2516     break;
2517   case 2:
2518     switch (numCorners) {
2519     case 3: /* triangle */
2520       *numFaceVertices = 2; /* Edge has 2 vertices */
2521       break;
2522     case 4: /* quadrilateral */
2523       *numFaceVertices = 2; /* Edge has 2 vertices */
2524       break;
2525     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2526       *numFaceVertices = 3; /* Edge has 3 vertices */
2527       break;
2528     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2529       *numFaceVertices = 3; /* Edge has 3 vertices */
2530       break;
2531     default:
2532       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2533     }
2534     break;
2535   case 3:
2536     switch (numCorners) {
2537     case 4: /* tetradehdron */
2538       *numFaceVertices = 3; /* Face has 3 vertices */
2539       break;
2540     case 6: /* tet cohesive cells */
2541       *numFaceVertices = 4; /* Face has 4 vertices */
2542       break;
2543     case 8: /* hexahedron */
2544       *numFaceVertices = 4; /* Face has 4 vertices */
2545       break;
2546     case 9: /* tet cohesive Lagrange cells */
2547       *numFaceVertices = 6; /* Face has 6 vertices */
2548       break;
2549     case 10: /* quadratic tetrahedron */
2550       *numFaceVertices = 6; /* Face has 6 vertices */
2551       break;
2552     case 12: /* hex cohesive Lagrange cells */
2553       *numFaceVertices = 6; /* Face has 6 vertices */
2554       break;
2555     case 18: /* quadratic tet cohesive Lagrange cells */
2556       *numFaceVertices = 6; /* Face has 6 vertices */
2557       break;
2558     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2559       *numFaceVertices = 9; /* Face has 9 vertices */
2560       break;
2561     default:
2562       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2563     }
2564     break;
2565   default:
2566     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2567   }
2568   PetscFunctionReturn(0);
2569 }
2570 
2571 #undef __FUNCT__
2572 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2573 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2574 {
2575   const PetscInt maxFaceCases = 30;
2576   PetscInt       numFaceCases = 0;
2577   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2578   PetscInt       *off, *adj;
2579   PetscInt       *neighborCells, *tmpClosure;
2580   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2581   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2582   PetscErrorCode ierr;
2583 
2584   PetscFunctionBegin;
2585   /* For parallel partitioning, I think you have to communicate supports */
2586   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2587   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2588   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2589   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2590   if (cEnd - cStart == 0) {
2591     if (numVertices) *numVertices = 0;
2592     if (offsets)   *offsets   = PETSC_NULL;
2593     if (adjacency) *adjacency = PETSC_NULL;
2594     PetscFunctionReturn(0);
2595   }
2596   numCells = cEnd - cStart;
2597   /* Setup face recognition */
2598   if (depth == 1) {
2599     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 */
2600 
2601     for (c = cStart; c < cEnd; ++c) {
2602       PetscInt corners;
2603 
2604       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2605       if (!cornersSeen[corners]) {
2606         PetscInt nFV;
2607 
2608         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2609         cornersSeen[corners] = 1;
2610 
2611         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2612 
2613         numFaceVertices[numFaceCases++] = nFV;
2614       }
2615     }
2616   }
2617   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2618   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2619   ierr         = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2620   ierr         = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2621   ierr         = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2622   /* Count neighboring cells */
2623   for (cell = cStart; cell < cEnd; ++cell) {
2624     PetscInt numNeighbors = maxNeighbors, n;
2625 
2626     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2627     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2628     for (n = 0; n < numNeighbors; ++n) {
2629       PetscInt       cellPair[2];
2630       PetscBool      found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2631       PetscInt       meetSize = 0;
2632       const PetscInt *meet    = PETSC_NULL;
2633 
2634       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2635       if (cellPair[0] == cellPair[1]) continue;
2636       if (!found) {
2637         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2638         if (meetSize) {
2639           PetscInt f;
2640 
2641           for (f = 0; f < numFaceCases; ++f) {
2642             if (numFaceVertices[f] == meetSize) {
2643               found = PETSC_TRUE;
2644               break;
2645             }
2646           }
2647         }
2648         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2649       }
2650       if (found) ++off[cell-cStart+1];
2651     }
2652   }
2653   /* Prefix sum */
2654   for (cell = 1; cell <= numCells; ++cell) off[cell] += off[cell-1];
2655 
2656   if (adjacency) {
2657     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2658     /* Get neighboring cells */
2659     for (cell = cStart; cell < cEnd; ++cell) {
2660       PetscInt numNeighbors = maxNeighbors, n;
2661       PetscInt cellOffset   = 0;
2662 
2663       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2664       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2665       for (n = 0; n < numNeighbors; ++n) {
2666         PetscInt       cellPair[2];
2667         PetscBool      found    = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2668         PetscInt       meetSize = 0;
2669         const PetscInt *meet    = PETSC_NULL;
2670 
2671         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2672         if (cellPair[0] == cellPair[1]) continue;
2673         if (!found) {
2674           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2675           if (meetSize) {
2676             PetscInt f;
2677 
2678             for (f = 0; f < numFaceCases; ++f) {
2679               if (numFaceVertices[f] == meetSize) {
2680                 found = PETSC_TRUE;
2681                 break;
2682               }
2683             }
2684           }
2685           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2686         }
2687         if (found) {
2688           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2689           ++cellOffset;
2690         }
2691       }
2692     }
2693   }
2694   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2695   if (numVertices) *numVertices = numCells;
2696   if (offsets)   *offsets   = off;
2697   if (adjacency) *adjacency = adj;
2698   PetscFunctionReturn(0);
2699 }
2700 
2701 #if defined(PETSC_HAVE_CHACO)
2702 #if defined(PETSC_HAVE_UNISTD_H)
2703 #include <unistd.h>
2704 #endif
2705 /* Chaco does not have an include file */
2706 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2707                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2708                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2709                        int mesh_dims[3], double *goal, int global_method, int local_method,
2710                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2711 
2712 extern int FREE_GRAPH;
2713 
2714 #undef __FUNCT__
2715 #define __FUNCT__ "DMPlexPartition_Chaco"
2716 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2717 {
2718   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2719   MPI_Comm       comm           = ((PetscObject) dm)->comm;
2720   int            nvtxs          = numVertices; /* number of vertices in full graph */
2721   int            *vwgts         = NULL;   /* weights for all vertices */
2722   float          *ewgts         = NULL;   /* weights for all edges */
2723   float          *x             = NULL, *y = NULL, *z = NULL; /* coordinates for inertial method */
2724   char           *outassignname = NULL;   /*  name of assignment output file */
2725   char           *outfilename   = NULL;   /* output file name */
2726   int            architecture   = 1;      /* 0 => hypercube, d => d-dimensional mesh */
2727   int            ndims_tot      = 0;      /* total number of cube dimensions to divide */
2728   int            mesh_dims[3];            /* dimensions of mesh of processors */
2729   double         *goal         = NULL;    /* desired set sizes for each set */
2730   int            global_method = 1;       /* global partitioning algorithm */
2731   int            local_method  = 1;       /* local partitioning algorithm */
2732   int            rqi_flag      = 0;       /* should I use RQI/Symmlq eigensolver? */
2733   int            vmax          = 200;     /* how many vertices to coarsen down to? */
2734   int            ndims         = 1;       /* number of eigenvectors (2^d sets) */
2735   double         eigtol        = 0.001;   /* tolerance on eigenvectors */
2736   long           seed          = 123636512; /* for random graph mutations */
2737   short int      *assignment;             /* Output partition */
2738   int            fd_stdout, fd_pipe[2];
2739   PetscInt       *points;
2740   PetscMPIInt    commSize;
2741   int            i, v, p;
2742   PetscErrorCode ierr;
2743 
2744   PetscFunctionBegin;
2745   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2746   if (!numVertices) {
2747     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2748     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2749     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2750     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2751     PetscFunctionReturn(0);
2752   }
2753   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2754   for (i = 0; i < start[numVertices]; ++i) ++adjacency[i];
2755 
2756   if (global_method == INERTIAL_METHOD) {
2757     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2758     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2759   }
2760   mesh_dims[0] = commSize;
2761   mesh_dims[1] = 1;
2762   mesh_dims[2] = 1;
2763   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2764   /* Chaco outputs to stdout. We redirect this to a buffer. */
2765   /* TODO: check error codes for UNIX calls */
2766 #if defined(PETSC_HAVE_UNISTD_H)
2767   {
2768     int piperet;
2769     piperet = pipe(fd_pipe);
2770     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2771     fd_stdout = dup(1);
2772     close(1);
2773     dup2(fd_pipe[1], 1);
2774   }
2775 #endif
2776   ierr = interface(nvtxs, (int*) start, (int*) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2777                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2778                    vmax, ndims, eigtol, seed);
2779 #if defined(PETSC_HAVE_UNISTD_H)
2780   {
2781     char msgLog[10000];
2782     int  count;
2783 
2784     fflush(stdout);
2785     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2786     if (count < 0) count = 0;
2787     msgLog[count] = 0;
2788     close(1);
2789     dup2(fd_stdout, 1);
2790     close(fd_stdout);
2791     close(fd_pipe[0]);
2792     close(fd_pipe[1]);
2793     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2794   }
2795 #endif
2796   /* Convert to PetscSection+IS */
2797   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2798   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2799   for (v = 0; v < nvtxs; ++v) {
2800     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2801   }
2802   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2803   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2804   for (p = 0, i = 0; p < commSize; ++p) {
2805     for (v = 0; v < nvtxs; ++v) {
2806       if (assignment[v] == p) points[i++] = v;
2807     }
2808   }
2809   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2810   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2811   if (global_method == INERTIAL_METHOD) {
2812     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2813   }
2814   ierr = PetscFree(assignment);CHKERRQ(ierr);
2815   for (i = 0; i < start[numVertices]; ++i) --adjacency[i];
2816   PetscFunctionReturn(0);
2817 }
2818 #endif
2819 
2820 #if defined(PETSC_HAVE_PARMETIS)
2821 #undef __FUNCT__
2822 #define __FUNCT__ "DMPlexPartition_ParMetis"
2823 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2824 {
2825   PetscFunctionBegin;
2826   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2827   PetscFunctionReturn(0);
2828 }
2829 #endif
2830 
2831 #undef __FUNCT__
2832 #define __FUNCT__ "DMPlexEnlargePartition"
2833 /* Expand the partition by BFS on the adjacency graph */
2834 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2835 {
2836   PetscHashI     h;
2837   const PetscInt *points;
2838   PetscInt       **tmpPoints, *newPoints, totPoints = 0;
2839   PetscInt       pStart, pEnd, part, q;
2840   PetscErrorCode ierr;
2841 
2842   PetscFunctionBegin;
2843   PetscHashICreate(h);
2844   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2845   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2846   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2847   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2848   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt*), &tmpPoints);CHKERRQ(ierr);
2849   for (part = pStart; part < pEnd; ++part) {
2850     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2851 
2852     PetscHashIClear(h);
2853     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2854     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2855     /* Add all existing points to h */
2856     for (p = 0; p < numPoints; ++p) {
2857       const PetscInt point = points[off+p];
2858       PetscHashIAdd(h, point, 1);
2859     }
2860     PetscHashISize(h, nP);
2861     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2862     /* Add all points in next BFS level */
2863     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2864     for (p = 0; p < numPoints; ++p) {
2865       const PetscInt point = points[off+p];
2866       PetscInt       s     = start[point], e = start[point+1], a;
2867 
2868       for (a = s; a < e; ++a) PetscHashIAdd(h, adjacency[a], 1);
2869     }
2870     PetscHashISize(h, numNewPoints);
2871     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2872     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2873     if (numNewPoints) PetscHashIGetKeys(h, n, tmpPoints[part]); /* Should not need this conditional */
2874     totPoints += numNewPoints;
2875   }
2876   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2877   PetscHashIDestroy(h);
2878   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2879   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2880   for (part = pStart, q = 0; part < pEnd; ++part) {
2881     PetscInt numPoints, p;
2882 
2883     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2884     for (p = 0; p < numPoints; ++p, ++q) newPoints[q] = tmpPoints[part][p];
2885     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2886   }
2887   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2888   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2889   PetscFunctionReturn(0);
2890 }
2891 
2892 #undef __FUNCT__
2893 #define __FUNCT__ "DMPlexCreatePartition"
2894 /*
2895   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2896 
2897   Collective on DM
2898 
2899   Input Parameters:
2900   + dm - The DM
2901   . height - The height for points in the partition
2902   - enlarge - Expand each partition with neighbors
2903 
2904   Output Parameters:
2905   + partSection - The PetscSection giving the division of points by partition
2906   . partition - The list of points by partition
2907   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2908   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2909 
2910   Level: developer
2911 
2912 .seealso DMPlexDistribute()
2913 */
2914 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2915 {
2916   PetscMPIInt    size;
2917   PetscErrorCode ierr;
2918 
2919   PetscFunctionBegin;
2920   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2921 
2922   *origPartSection = PETSC_NULL;
2923   *origPartition   = PETSC_NULL;
2924   if (size == 1) {
2925     PetscInt *points;
2926     PetscInt cStart, cEnd, c;
2927 
2928     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2929     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2930     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2931     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2932     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2933     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2934     for (c = cStart; c < cEnd; ++c) points[c] = c;
2935     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2936     PetscFunctionReturn(0);
2937   }
2938   if (height == 0) {
2939     PetscInt numVertices;
2940     PetscInt *start     = PETSC_NULL;
2941     PetscInt *adjacency = PETSC_NULL;
2942 
2943     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2944     if (1) {
2945 #if defined(PETSC_HAVE_CHACO)
2946       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2947 #endif
2948     } else {
2949 #if defined(PETSC_HAVE_PARMETIS)
2950       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2951 #endif
2952     }
2953     if (enlarge) {
2954       *origPartSection = *partSection;
2955       *origPartition   = *partition;
2956 
2957       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2958     }
2959     ierr = PetscFree(start);CHKERRQ(ierr);
2960     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2961 # if 0
2962   } else if (height == 1) {
2963     /* Build the dual graph for faces and partition the hypergraph */
2964     PetscInt numEdges;
2965 
2966     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2967     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2968     destroyCSR(numEdges, start, adjacency);
2969 #endif
2970   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2971   PetscFunctionReturn(0);
2972 }
2973 
2974 #undef __FUNCT__
2975 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2976 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2977 {
2978   /* const PetscInt  height = 0; */
2979   const PetscInt *partArray;
2980   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2981   PetscInt       rStart, rEnd, rank, maxPartSize = 0, newSize;
2982   PetscErrorCode ierr;
2983 
2984   PetscFunctionBegin;
2985   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2986   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2987   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2988   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2989   for (rank = rStart; rank < rEnd; ++rank) {
2990     PetscInt partSize = 0;
2991     PetscInt numPoints, offset, p;
2992 
2993     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2994     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2995     for (p = 0; p < numPoints; ++p) {
2996       PetscInt point    = partArray[offset+p], closureSize, c;
2997       PetscInt *closure = PETSC_NULL;
2998 
2999       /* TODO Include support for height > 0 case */
3000       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3001       /* Merge into existing points */
3002       if (partSize+closureSize > maxPartSize) {
3003         PetscInt *tmpPoints;
3004 
3005         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
3006         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
3007         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3008         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3009 
3010         partPoints = tmpPoints;
3011       }
3012       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3013       partSize += closureSize;
3014 
3015       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3016       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3017     }
3018     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3019   }
3020   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3021   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3022   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3023 
3024   for (rank = rStart; rank < rEnd; ++rank) {
3025     PetscInt partSize = 0, newOffset;
3026     PetscInt numPoints, offset, p;
3027 
3028     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3029     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3030     for (p = 0; p < numPoints; ++p) {
3031       PetscInt point    = partArray[offset+p], closureSize, c;
3032       PetscInt *closure = PETSC_NULL;
3033 
3034       /* TODO Include support for height > 0 case */
3035       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3036       /* Merge into existing points */
3037       for (c = 0; c < closureSize; ++c) partPoints[partSize+c] = closure[c*2];
3038       partSize += closureSize;
3039 
3040       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3041       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3042     }
3043     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3044     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3045   }
3046   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3047   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3048   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3049   PetscFunctionReturn(0);
3050 }
3051 
3052 #undef __FUNCT__
3053 #define __FUNCT__ "DMPlexDistributeField"
3054 /*
3055   Input Parameters:
3056 . originalSection
3057 , originalVec
3058 
3059   Output Parameters:
3060 . newSection
3061 . newVec
3062 */
3063 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3064 {
3065   PetscSF        fieldSF;
3066   PetscInt       *remoteOffsets, fieldSize;
3067   PetscScalar    *originalValues, *newValues;
3068   PetscErrorCode ierr;
3069 
3070   PetscFunctionBegin;
3071   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3072 
3073   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3074   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3075   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3076 
3077   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3078   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3079   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3080   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3081   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3082   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3083   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3084   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3085   PetscFunctionReturn(0);
3086 }
3087 
3088 #undef __FUNCT__
3089 #define __FUNCT__ "DMPlexDistribute"
3090 /*@C
3091   DMPlexDistribute - Distributes the mesh and any associated sections.
3092 
3093   Not Collective
3094 
3095   Input Parameter:
3096 + dm  - The original DMPlex object
3097 . partitioner - The partitioning package, or NULL for the default
3098 - overlap - The overlap of partitions, 0 is the default
3099 
3100   Output Parameter:
3101 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3102 
3103   Note: If the mesh was not distributed, the return value is PETSC_NULL
3104 
3105   Level: intermediate
3106 
3107 .keywords: mesh, elements
3108 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3109 @*/
3110 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3111 {
3112   DM_Plex                *mesh  = (DM_Plex*) dm->data, *pmesh;
3113   MPI_Comm               comm   = ((PetscObject) dm)->comm;
3114   const PetscInt         height = 0;
3115   PetscInt               dim, numRemoteRanks;
3116   IS                     origCellPart,        cellPart,        part;
3117   PetscSection           origCellPartSection, cellPartSection, partSection;
3118   PetscSFNode            *remoteRanks;
3119   PetscSF                partSF, pointSF, coneSF;
3120   ISLocalToGlobalMapping renumbering;
3121   PetscSection           originalConeSection, newConeSection;
3122   PetscInt               *remoteOffsets;
3123   PetscInt               *cones, *newCones, newConesSize;
3124   PetscBool              flg;
3125   PetscMPIInt            rank, numProcs, p;
3126   PetscErrorCode         ierr;
3127 
3128   PetscFunctionBegin;
3129   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3130   PetscValidPointer(dmParallel,4);
3131 
3132   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3133   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3134   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3135 
3136   *dmParallel = PETSC_NULL;
3137   if (numProcs == 1) PetscFunctionReturn(0);
3138 
3139   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3140   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3141   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3142   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3143   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3144   if (!rank) numRemoteRanks = numProcs;
3145   else       numRemoteRanks = 0;
3146   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3147   for (p = 0; p < numRemoteRanks; ++p) {
3148     remoteRanks[p].rank  = p;
3149     remoteRanks[p].index = 0;
3150   }
3151   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3152   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3153   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3154   if (flg) {
3155     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3156     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3157     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3158     if (origCellPart) {
3159       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3160       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3161       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3162     }
3163     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3164   }
3165   /* Close the partition over the mesh */
3166   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3167   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3168   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3169   /* Create new mesh */
3170   ierr  = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3171   ierr  = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3172   ierr  = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3173   pmesh = (DM_Plex*) (*dmParallel)->data;
3174   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3175   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3176   if (flg) {
3177     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3178     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3179     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3180     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3181     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3182     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3183   }
3184   /* Distribute cone section */
3185   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3186   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3187   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3188   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3189   {
3190     PetscInt pStart, pEnd, p;
3191 
3192     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3193     for (p = pStart; p < pEnd; ++p) {
3194       PetscInt coneSize;
3195       ierr               = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3196       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3197     }
3198   }
3199   /* Communicate and renumber cones */
3200   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3201   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3202   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3203   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3204   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3205   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3206   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3207   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3208   if (flg) {
3209     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3210     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3211     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3212     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3213     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3214   }
3215   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3216   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3217   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3218   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3219   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3220   /* Create supports and stratify sieve */
3221   {
3222     PetscInt pStart, pEnd;
3223 
3224     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3225     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3226   }
3227   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3228   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3229   /* Distribute Coordinates */
3230   {
3231     PetscSection originalCoordSection, newCoordSection;
3232     Vec          originalCoordinates, newCoordinates;
3233     const char   *name;
3234 
3235     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3236     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3237     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3238     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3239     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3240     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3241 
3242     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3243     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3244     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3245   }
3246   /* Distribute labels */
3247   {
3248     DMLabel  next      = mesh->labels, newNext = pmesh->labels;
3249     PetscInt numLabels = 0, l;
3250 
3251     /* Bcast number of labels */
3252     while (next) {
3253       ++numLabels; next = next->next;
3254     }
3255     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3256     next = mesh->labels;
3257     for (l = 0; l < numLabels; ++l) {
3258       DMLabel        newLabel;
3259       const PetscInt *partArray;
3260       char           *name;
3261       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3262       PetscMPIInt    *sendcnts     = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3263       PetscInt       nameSize, s, p;
3264       PetscBool      isdepth;
3265       size_t         len = 0;
3266 
3267       /* Bcast name (could filter for no points) */
3268       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3269       nameSize = len;
3270       ierr     = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3271       ierr     = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3272       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3273       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3274       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3275       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3276       ierr           = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3277       newLabel->name = name;
3278       /* Bcast numStrata (could filter for no points in stratum) */
3279       if (!rank) newLabel->numStrata = next->numStrata;
3280       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3281       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3282                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3283                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3284       /* Bcast stratumValues (could filter for no points in stratum) */
3285       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3286       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3287       /* Find size on each process and Scatter */
3288       if (!rank) {
3289         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3290         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3291         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3292         for (s = 0; s < next->numStrata; ++s) {
3293           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3294             const PetscInt point = next->points[p];
3295             PetscInt       proc;
3296 
3297             for (proc = 0; proc < numProcs; ++proc) {
3298               PetscInt dof, off, pPart;
3299 
3300               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3301               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3302               for (pPart = off; pPart < off+dof; ++pPart) {
3303                 if (partArray[pPart] == point) {
3304                   ++stratumSizes[proc*next->numStrata+s];
3305                   break;
3306                 }
3307               }
3308             }
3309           }
3310         }
3311         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3312       }
3313       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3314       /* Calculate stratumOffsets */
3315       newLabel->stratumOffsets[0] = 0;
3316       for (s = 0; s < newLabel->numStrata; ++s) {
3317         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3318       }
3319       /* Pack points and Scatter */
3320       if (!rank) {
3321         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3322         displs[0] = 0;
3323         for (p = 0; p < numProcs; ++p) {
3324           sendcnts[p] = 0;
3325           for (s = 0; s < next->numStrata; ++s) {
3326             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3327           }
3328           offsets[p]  = displs[p];
3329           displs[p+1] = displs[p] + sendcnts[p];
3330         }
3331         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3332         for (s = 0; s < next->numStrata; ++s) {
3333           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3334             const PetscInt point = next->points[p];
3335             PetscInt       proc;
3336 
3337             for (proc = 0; proc < numProcs; ++proc) {
3338               PetscInt dof, off, pPart;
3339 
3340               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3341               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3342               for (pPart = off; pPart < off+dof; ++pPart) {
3343                 if (partArray[pPart] == point) {
3344                   points[offsets[proc]++] = point;
3345                   break;
3346                 }
3347               }
3348             }
3349           }
3350         }
3351       }
3352       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3353       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3354       ierr = PetscFree(points);CHKERRQ(ierr);
3355       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3356       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3357       /* Renumber points */
3358       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3359       /* Sort points */
3360       for (s = 0; s < newLabel->numStrata; ++s) {
3361         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3362       }
3363       /* Insert into list */
3364       if (newNext) newNext->next = newLabel;
3365       else pmesh->labels = newLabel;
3366       newNext = newLabel;
3367       if (!rank) next = next->next;
3368     }
3369   }
3370   /* Cleanup Partition */
3371   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3372   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3373   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3374   ierr = ISDestroy(&part);CHKERRQ(ierr);
3375   /* Create point SF for parallel mesh */
3376   {
3377     const PetscInt *leaves;
3378     PetscSFNode    *remotePoints, *rowners, *lowners;
3379     PetscInt       numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3380     PetscInt       pStart, pEnd;
3381 
3382     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3383     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3384     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3385     for (p=0; p<numRoots; p++) {
3386       rowners[p].rank  = -1;
3387       rowners[p].index = -1;
3388     }
3389     if (origCellPart) {
3390       /* Make sure cells in the original partition are not assigned to other procs */
3391       const PetscInt *origCells;
3392 
3393       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3394       for (p = 0; p < numProcs; ++p) {
3395         PetscInt dof, off, d;
3396 
3397         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3398         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3399         for (d = off; d < off+dof; ++d) {
3400           rowners[origCells[d]].rank = p;
3401         }
3402       }
3403       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3404     }
3405     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3406     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3407 
3408     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3409     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3410     for (p = 0; p < numLeaves; ++p) {
3411       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3412         lowners[p].rank  = rank;
3413         lowners[p].index = leaves ? leaves[p] : p;
3414       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3415         lowners[p].rank  = -2;
3416         lowners[p].index = -2;
3417       }
3418     }
3419     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3420       rowners[p].rank  = -3;
3421       rowners[p].index = -3;
3422     }
3423     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3424     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3425     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3426     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3427     for (p = 0; p < numLeaves; ++p) {
3428       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3429       if (lowners[p].rank != rank) ++numGhostPoints;
3430     }
3431     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3432     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3433     for (p = 0, gp = 0; p < numLeaves; ++p) {
3434       if (lowners[p].rank != rank) {
3435         ghostPoints[gp]        = leaves ? leaves[p] : p;
3436         remotePoints[gp].rank  = lowners[p].rank;
3437         remotePoints[gp].index = lowners[p].index;
3438         ++gp;
3439       }
3440     }
3441     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3442     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3443     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3444   }
3445   /* Cleanup */
3446   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3447   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3448   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3449   PetscFunctionReturn(0);
3450 }
3451 
3452 #undef __FUNCT__
3453 #define __FUNCT__ "DMPlexRenumber_Private"
3454 /*
3455   Reasons to renumber:
3456 
3457   1) Permute points, e.g. bandwidth reduction (Renumber)
3458 
3459     a) Must not mix strata
3460 
3461   2) Shift numbers for point insertion (Shift)
3462 
3463     a) Want operation brken into parts so that insertion can be interleaved
3464 
3465   renumbering - An IS which provides the new numbering
3466 */
3467 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3468 {
3469   PetscFunctionBegin;
3470   PetscFunctionReturn(0);
3471 }
3472 
3473 #undef __FUNCT__
3474 #define __FUNCT__ "DMPlexShiftPoint_Private"
3475 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3476 {
3477   if (depth < 0) return p;
3478   /* Cells    */ if (p < depthEnd[depth])   return p;
3479   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3480   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3481   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3482 }
3483 
3484 #undef __FUNCT__
3485 #define __FUNCT__ "DMPlexShiftSizes_Private"
3486 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3487 {
3488   PetscInt       *depthEnd;
3489   PetscInt       depth = 0, d, pStart, pEnd, p;
3490   PetscErrorCode ierr;
3491 
3492   PetscFunctionBegin;
3493   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3494   if (depth < 0) PetscFunctionReturn(0);
3495   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3496   /* Step 1: Expand chart */
3497   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3498   for (d = 0; d <= depth; ++d) {
3499     pEnd += depthShift[d];
3500     ierr  = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3501   }
3502   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3503   /* Step 2: Set cone and support sizes */
3504   for (d = 0; d <= depth; ++d) {
3505     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3506     for (p = pStart; p < pEnd; ++p) {
3507       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3508       PetscInt size;
3509 
3510       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3511       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3512       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3513       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3514     }
3515   }
3516   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3517   PetscFunctionReturn(0);
3518 }
3519 
3520 #undef __FUNCT__
3521 #define __FUNCT__ "DMPlexShiftPoints_Private"
3522 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3523 {
3524   PetscInt       *depthEnd, *newpoints;
3525   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3526   PetscErrorCode ierr;
3527 
3528   PetscFunctionBegin;
3529   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3530   if (depth < 0) PetscFunctionReturn(0);
3531   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3532   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3533   for (d = 0; d <= depth; ++d) {
3534     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3535   }
3536   /* Step 5: Set cones and supports */
3537   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3538   for (p = pStart; p < pEnd; ++p) {
3539     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3540     PetscInt       size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3541 
3542     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3543     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3544     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3545     for (i = 0; i < size; ++i) {
3546       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3547     }
3548     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3549     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3550     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3551     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3552     for (i = 0; i < size; ++i) {
3553       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3554     }
3555     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3556   }
3557   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3558   PetscFunctionReturn(0);
3559 }
3560 
3561 #undef __FUNCT__
3562 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3563 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3564 {
3565   PetscSection   coordSection, newCoordSection;
3566   Vec            coordinates, newCoordinates;
3567   PetscScalar    *coords, *newCoords;
3568   PetscInt       *depthEnd, coordSize;
3569   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3570   PetscErrorCode ierr;
3571 
3572   PetscFunctionBegin;
3573   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3574   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3575   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3576   for (d = 0; d <= depth; ++d) {
3577     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3578   }
3579   /* Step 8: Convert coordinates */
3580   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3581   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3582   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3583   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3584   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3585   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3586   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3587   for (v = vStartNew; v < vEndNew; ++v) {
3588     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3589     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3590   }
3591   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3592   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3593   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3594   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3595   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3596   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3597   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3598   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3599   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3600   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3601   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3602   for (v = vStart; v < vEnd; ++v) {
3603     PetscInt dof, off, noff, d;
3604 
3605     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3606     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3607     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3608     for (d = 0; d < dof; ++d) {
3609       newCoords[noff+d] = coords[off+d];
3610     }
3611   }
3612   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3613   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3614   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3615   PetscFunctionReturn(0);
3616 }
3617 
3618 #undef __FUNCT__
3619 #define __FUNCT__ "DMPlexShiftSF_Private"
3620 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3621 {
3622   PetscInt          *depthEnd;
3623   PetscInt          depth = 0, d;
3624   PetscSF           sfPoint, sfPointNew;
3625   const PetscSFNode *remotePoints;
3626   PetscSFNode       *gremotePoints;
3627   const PetscInt    *localPoints;
3628   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3629   PetscInt          numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3630   PetscMPIInt       numProcs;
3631   PetscErrorCode    ierr;
3632 
3633   PetscFunctionBegin;
3634   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3635   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3636   for (d = 0; d <= depth; ++d) {
3637     totShift += depthShift[d];
3638     ierr      = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3639   }
3640   /* Step 9: Convert pointSF */
3641   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3642   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3643   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3644   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3645   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3646   if (numRoots >= 0) {
3647     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3648     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3649     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3650     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3651     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3652     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3653     for (l = 0; l < numLeaves; ++l) {
3654       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3655       gremotePoints[l].rank  = remotePoints[l].rank;
3656       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3657     }
3658     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3659     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3660   }
3661   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3662   PetscFunctionReturn(0);
3663 }
3664 
3665 #undef __FUNCT__
3666 #define __FUNCT__ "DMPlexShiftLabels_Private"
3667 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3668 {
3669   PetscSF           sfPoint;
3670   DMLabel           vtkLabel, ghostLabel;
3671   PetscInt          *depthEnd;
3672   const PetscSFNode *leafRemote;
3673   const PetscInt    *leafLocal;
3674   PetscInt          depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3675   PetscMPIInt       rank;
3676   PetscErrorCode    ierr;
3677 
3678   PetscFunctionBegin;
3679   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3680   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3681   for (d = 0; d <= depth; ++d) {
3682     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3683   }
3684   /* Step 10: Convert labels */
3685   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3686   for (l = 0; l < numLabels; ++l) {
3687     DMLabel        label, newlabel;
3688     const char     *lname;
3689     PetscBool      isDepth;
3690     IS             valueIS;
3691     const PetscInt *values;
3692     PetscInt       numValues, val;
3693 
3694     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3695     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3696     if (isDepth) continue;
3697     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3698     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3699     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3700     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3701     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3702     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3703     for (val = 0; val < numValues; ++val) {
3704       IS             pointIS;
3705       const PetscInt *points;
3706       PetscInt       numPoints, p;
3707 
3708       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3709       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3710       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3711       for (p = 0; p < numPoints; ++p) {
3712         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3713 
3714         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3715       }
3716       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3717       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3718     }
3719     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3720     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3721   }
3722   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3723   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3724   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3725   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3726   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3727   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3728   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3729   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3730   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3731   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3732   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3733     for (; c < leafLocal[l] && c < cEnd; ++c) {
3734       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3735     }
3736     if (leafLocal[l] >= cEnd) break;
3737     if (leafRemote[l].rank == rank) {
3738       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3739     } else {
3740       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3741     }
3742   }
3743   for (; c < cEnd; ++c) {
3744     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3745   }
3746   if (0) {
3747     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3748     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3749     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3750   }
3751   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3752   for (f = fStart; f < fEnd; ++f) {
3753     PetscInt numCells;
3754 
3755     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3756     if (numCells < 2) {
3757       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3758     } else {
3759       const PetscInt *cells = PETSC_NULL;
3760       PetscInt       vA, vB;
3761 
3762       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3763       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3764       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3765       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3766     }
3767   }
3768   if (0) {
3769     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3770     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3771     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3772   }
3773   PetscFunctionReturn(0);
3774 }
3775 
3776 #undef __FUNCT__
3777 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3778 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3779 {
3780   DMLabel        label;
3781   IS             valueIS;
3782   const PetscInt *values;
3783   PetscInt       *depthShift;
3784   PetscInt       depth = 0, numFS, fs, ghostCell, cEnd, c;
3785   PetscErrorCode ierr;
3786 
3787   PetscFunctionBegin;
3788   /* Count ghost cells */
3789   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3790   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3791   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3792   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3793 
3794   *numGhostCells = 0;
3795   for (fs = 0; fs < numFS; ++fs) {
3796     PetscInt numBdFaces;
3797 
3798     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3799 
3800     *numGhostCells += numBdFaces;
3801   }
3802   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3803   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3804   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3805   if (depth >= 0) depthShift[depth] = *numGhostCells;
3806   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3807   /* Step 3: Set cone/support sizes for new points */
3808   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3809   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3810     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3811   }
3812   for (fs = 0; fs < numFS; ++fs) {
3813     IS             faceIS;
3814     const PetscInt *faces;
3815     PetscInt       numFaces, f;
3816 
3817     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3818     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3819     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3820     for (f = 0; f < numFaces; ++f) {
3821       PetscInt size;
3822 
3823       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3824       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3825       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3826     }
3827     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3828     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3829   }
3830   /* Step 4: Setup ghosted DM */
3831   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3832   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3833   /* Step 6: Set cones and supports for new points */
3834   ghostCell = cEnd;
3835   for (fs = 0; fs < numFS; ++fs) {
3836     IS             faceIS;
3837     const PetscInt *faces;
3838     PetscInt       numFaces, f;
3839 
3840     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3841     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3842     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3843     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3844       PetscInt newFace = faces[f] + *numGhostCells;
3845 
3846       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3847       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3848     }
3849     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3850     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3851   }
3852   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3853   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3854   /* Step 7: Stratify */
3855   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3856   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3857   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3858   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3859   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3860   PetscFunctionReturn(0);
3861 }
3862 
3863 #undef __FUNCT__
3864 #define __FUNCT__ "DMPlexConstructGhostCells"
3865 /*@C
3866   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3867 
3868   Collective on dm
3869 
3870   Input Parameters:
3871 + dm - The original DM
3872 - labelName - The label specifying the boundary faces (this could be auto-generated)
3873 
3874   Output Parameters:
3875 + numGhostCells - The number of ghost cells added to the DM
3876 - dmGhosted - The new DM
3877 
3878   Level: developer
3879 
3880 .seealso: DMCreate()
3881 */
3882 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3883 {
3884   DM             gdm;
3885   PetscInt       dim;
3886   PetscErrorCode ierr;
3887 
3888   PetscFunctionBegin;
3889   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3890   PetscValidPointer(numGhostCells, 3);
3891   PetscValidPointer(dmGhosted, 4);
3892   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3893   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3894   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3895   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3896   switch (dim) {
3897   case 2:
3898     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3899     break;
3900   default:
3901     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3902   }
3903   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3904   *dmGhosted = gdm;
3905   PetscFunctionReturn(0);
3906 }
3907 
3908 #undef __FUNCT__
3909 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3910 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, const char labelName[], DM sdm)
3911 {
3912   MPI_Comm       comm = ((PetscObject) dm)->comm;
3913   DMLabel        label;
3914   IS             valueIS, *pointIS;
3915   const PetscInt *values, **splitPoints;
3916   PetscSection   coordSection;
3917   Vec            coordinates;
3918   PetscScalar    *coords;
3919   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3920   PetscInt       shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3921   PetscErrorCode ierr;
3922 
3923   PetscFunctionBegin;
3924   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3925   /* Count split points and add cohesive cells */
3926   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3927   if (label) {
3928     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3929     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3930     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3931   }
3932   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3933   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3934   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3935   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3936   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3937   for (d = 0; d <= depth; ++d) {
3938     ierr              = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3939     numSplitPoints[d] = 0;
3940     splitPoints[d]    = PETSC_NULL;
3941     pointIS[d]        = PETSC_NULL;
3942   }
3943   for (sp = 0; sp < numSP; ++sp) {
3944     const PetscInt dep = values[sp];
3945 
3946     if ((dep < 0) || (dep > depth)) continue;
3947     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3948     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3949     if (pointIS[dep]) {
3950       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3951       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3952     }
3953   }
3954   if (depth >= 0) {
3955     /* Calculate number of additional points */
3956     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3957     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3958     /* Calculate hybrid bound for each dimension */
3959     pMaxNew[0] += depthShift[depth];
3960     if (depth > 1) pMaxNew[dim-1] += depthShift[depth] + depthShift[0];
3961     if (depth > 2) pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];
3962 
3963     /* Calculate point offset for each dimension */
3964     depthOffset[depth] = 0;
3965     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3966     if (depth > 1) depthOffset[dim-1] = depthOffset[0]     + depthShift[0];
3967     if (depth > 2) depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];
3968   }
3969   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3970   /* Step 3: Set cone/support sizes for new points */
3971   for (dep = 0; dep <= depth; ++dep) {
3972     for (p = 0; p < numSplitPoints[dep]; ++p) {
3973       const PetscInt oldp   = splitPoints[dep][p];
3974       const PetscInt newp   = depthOffset[dep] + oldp;
3975       const PetscInt splitp = pMaxNew[dep] + p;
3976       const PetscInt *support;
3977       PetscInt       coneSize, supportSize, q, e;
3978 
3979       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3980       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3981       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3982       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3983       if (dep == depth-1) {
3984         const PetscInt ccell = pMaxNew[depth] + p;
3985         /* Add cohesive cells, they are prisms */
3986         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3987       } else if (dep == 0) {
3988         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3989 
3990         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3991         /* Split old vertex: Edges in old split faces and new cohesive edge */
3992         for (e = 0, q = 0; e < supportSize; ++e) {
3993           PetscInt val;
3994 
3995           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3996           if ((val == 1) || (val == (shift + 1))) ++q;
3997         }
3998         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3999         /* Split new vertex: Edges in new split faces and new cohesive edge */
4000         for (e = 0, q = 0; e < supportSize; ++e) {
4001           PetscInt val;
4002 
4003           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4004           if ((val == 1) || (val == -(shift + 1))) ++q;
4005         }
4006         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4007         /* Add cohesive edges */
4008         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4009         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4010       } else if (dep == dim-2) {
4011         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4012         /* Split old edge: Faces in positive side cells and old split faces */
4013         for (e = 0, q = 0; e < supportSize; ++e) {
4014           PetscInt val;
4015 
4016           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4017           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4018         }
4019         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4020         /* Split new edge: Faces in negative side cells and new split faces */
4021         for (e = 0, q = 0; e < supportSize; ++e) {
4022           PetscInt val;
4023 
4024           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4025           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4026         }
4027         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4028       }
4029     }
4030   }
4031   /* Step 4: Setup split DM */
4032   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4033   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4034   /* Step 6: Set cones and supports for new points */
4035   for (dep = 0; dep <= depth; ++dep) {
4036     for (p = 0; p < numSplitPoints[dep]; ++p) {
4037       const PetscInt oldp   = splitPoints[dep][p];
4038       const PetscInt newp   = depthOffset[dep] + oldp;
4039       const PetscInt splitp = pMaxNew[dep] + p;
4040       const PetscInt *cone, *support, *ornt;
4041       PetscInt       coneSize, supportSize, q, v, e, s;
4042 
4043       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4044       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4045       ierr = DMPlexGetConeOrientation(dm, oldp, &ornt);CHKERRQ(ierr);
4046       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4047       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4048       if (dep == depth-1) {
4049         const PetscInt ccell = pMaxNew[depth] + p;
4050         const PetscInt *supportF;
4051 
4052         /* Split face:       copy in old face to new face to start */
4053         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4054         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4055         /* Split old face:   old vertices/edges in cone so no change */
4056         /* Split new face:   new vertices/edges in cone */
4057         for (q = 0; q < coneSize; ++q) {
4058           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4059 
4060           coneNew[2+q] = pMaxNew[dim-2] + v;
4061         }
4062         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4063         ierr = DMPlexSetConeOrientation(sdm, splitp, ornt);CHKERRQ(ierr);
4064         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4065         coneNew[0] = newp;
4066         coneNew[1] = splitp;
4067         for (q = 0; q < coneSize; ++q) {
4068           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4069         }
4070         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4071 
4072 
4073         for (s = 0; s < supportSize; ++s) {
4074           PetscInt val;
4075 
4076           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4077           if (val < 0) {
4078             /* Split old face:   Replace negative side cell with cohesive cell */
4079             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4080           } else {
4081             /* Split new face:   Replace positive side cell with cohesive cell */
4082             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4083           }
4084         }
4085       } else if (dep == 0) {
4086         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4087 
4088         /* Split old vertex: Edges in old split faces and new cohesive edge */
4089         for (e = 0, q = 0; e < supportSize; ++e) {
4090           PetscInt val;
4091 
4092           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4093           if ((val == 1) || (val == (shift + 1))) {
4094             supportNew[q++] = depthOffset[1] + support[e];
4095           }
4096         }
4097         supportNew[q] = cedge;
4098 
4099         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4100         /* Split new vertex: Edges in new split faces and new cohesive edge */
4101         for (e = 0, q = 0; e < supportSize; ++e) {
4102           PetscInt val, edge;
4103 
4104           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4105           if (val == 1) {
4106             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4107             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4108             supportNew[q++] = pMaxNew[1] + edge;
4109           } else if (val == -(shift + 1)) {
4110             supportNew[q++] = depthOffset[1] + support[e];
4111           }
4112         }
4113         supportNew[q] = cedge;
4114         ierr          = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4115         /* Cohesive edge:    Old and new split vertex, punting on support */
4116         coneNew[0] = newp;
4117         coneNew[1] = splitp;
4118         ierr       = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4119       } else if (dep == dim-2) {
4120         /* Split old edge:   old vertices in cone so no change */
4121         /* Split new edge:   new vertices in cone */
4122         for (q = 0; q < coneSize; ++q) {
4123           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4124 
4125           coneNew[q] = pMaxNew[dim-3] + v;
4126         }
4127         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4128         /* Split old edge: Faces in positive side cells and old split faces */
4129         for (e = 0, q = 0; e < supportSize; ++e) {
4130           PetscInt val;
4131 
4132           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4133           if ((val == dim-1) || (val == (shift + dim-1))) {
4134             supportNew[q++] = depthOffset[dim-1] + support[e];
4135           }
4136         }
4137         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4138         /* Split new edge: Faces in negative side cells and new split faces */
4139         for(e = 0, q = 0; e < supportSize; ++e) {
4140           PetscInt val, face;
4141 
4142           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4143           if (val == dim-1) {
4144             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4145             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4146             supportNew[q++] = pMaxNew[dim-1] + face;
4147           } else if (val == -(shift + dim-1)) {
4148             supportNew[q++] = depthOffset[dim-1] + support[e];
4149           }
4150         }
4151         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4152       }
4153     }
4154   }
4155   /* Step 6b: Replace split points in negative side cones */
4156   for (sp = 0; sp < numSP; ++sp) {
4157     PetscInt       dep = values[sp];
4158     IS             pIS;
4159     PetscInt       numPoints;
4160     const PetscInt *points;
4161 
4162     if (dep >= 0) continue;
4163     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4164     if (!pIS) continue;
4165     dep  = -dep - shift;
4166     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4167     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4168     for (p = 0; p < numPoints; ++p) {
4169       const PetscInt  oldp = points[p];
4170       const PetscInt  newp = depthOffset[dep] + oldp;
4171       const PetscInt *cone;
4172       PetscInt        coneSize, c;
4173       PetscBool       replaced = PETSC_FALSE;
4174 
4175       /* Negative edge: replace split vertex */
4176       /* Negative cell: replace split face */
4177       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4178       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4179       for (c = 0; c < coneSize; ++c) {
4180         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4181         PetscInt       csplitp, cp, val;
4182 
4183         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4184         if (val == dep-1) {
4185           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4186           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4187           csplitp  = pMaxNew[dep-1] + cp;
4188           ierr     = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4189           replaced = PETSC_TRUE;
4190         }
4191       }
4192       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4193     }
4194     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4195     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4196   }
4197   /* Step 7: Stratify */
4198   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4199   /* Step 8: Coordinates */
4200   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4201   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4202   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4203   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4204   for (v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4205     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4206     const PetscInt splitp = pMaxNew[0] + v;
4207     PetscInt       dof, off, soff, d;
4208 
4209     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4210     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4211     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4212     for (d = 0; d < dof; ++d) coords[soff+d] = coords[off+d];
4213   }
4214   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4215   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4216   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4217   /* Step 10: Labels */
4218   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4219   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4220   for (dep = 0; dep <= depth; ++dep) {
4221     for (p = 0; p < numSplitPoints[dep]; ++p) {
4222       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4223       const PetscInt splitp = pMaxNew[dep] + p;
4224       PetscInt       l;
4225 
4226       for (l = 0; l < numLabels; ++l) {
4227         DMLabel    label;
4228         const char *lname;
4229         PetscInt   val;
4230 
4231         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4232         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4233         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4234         if (val >= 0) {
4235           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4236           if (dep == 0) {
4237             const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4238             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4239           }
4240         }
4241       }
4242     }
4243   }
4244   for (sp = 0; sp < numSP; ++sp) {
4245     const PetscInt dep = values[sp];
4246 
4247     if ((dep < 0) || (dep > depth)) continue;
4248     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4249     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4250   }
4251   if (label) {
4252     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4253     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4254   }
4255   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4256   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4257   PetscFunctionReturn(0);
4258 }
4259 
4260 #undef __FUNCT__
4261 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4262 /*@C
4263   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4264 
4265   Collective on dm
4266 
4267   Input Parameters:
4268 + dm - The original DM
4269 - labelName - The label specifying the boundary faces (this could be auto-generated)
4270 
4271   Output Parameters:
4272 - dmSplit - The new DM
4273 
4274   Level: developer
4275 
4276 .seealso: DMCreate()
4277 */
4278 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4279 {
4280   DM             sdm;
4281   PetscInt       dim;
4282   PetscErrorCode ierr;
4283 
4284   PetscFunctionBegin;
4285   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4286   PetscValidPointer(dmSplit, 4);
4287   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4288   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4289   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4290   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4291   switch (dim) {
4292   case 2:
4293   case 3:
4294     ierr = DMPlexConstructCohesiveCells_Private(dm, labelName, sdm);CHKERRQ(ierr);
4295     break;
4296   default:
4297     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4298   }
4299   *dmSplit = sdm;
4300   PetscFunctionReturn(0);
4301 }
4302 
4303 #undef __FUNCT__
4304 #define __FUNCT__ "DMLabelCohesiveComplete"
4305 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4306 {
4307   IS             dimIS;
4308   const PetscInt *points;
4309   PetscInt       shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4310   PetscErrorCode ierr;
4311 
4312   PetscFunctionBegin;
4313   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4314   /* Cell orientation for face gives the side of the fault */
4315   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4316   if (!dimIS) PetscFunctionReturn(0);
4317   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4318   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4319   for (p = 0; p < numPoints; ++p) {
4320     const PetscInt *support;
4321     PetscInt       supportSize, s;
4322 
4323     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4324     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4325     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4326     for (s = 0; s < supportSize; ++s) {
4327       const PetscInt *cone, *ornt;
4328       PetscInt       coneSize, c;
4329       PetscBool      pos = PETSC_TRUE;
4330 
4331       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4332       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4333       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4334       for(c = 0; c < coneSize; ++c) {
4335         if (cone[c] == points[p]) {
4336           if (ornt[c] >= 0) {
4337             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4338           } else {
4339             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4340             pos  = PETSC_FALSE;
4341           }
4342           break;
4343         }
4344       }
4345       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]);
4346       /* Put faces touching the fault in the label */
4347       for (c = 0; c < coneSize; ++c) {
4348         const PetscInt point = cone[c];
4349 
4350         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4351         if (val == -1) {
4352           PetscInt *closure = PETSC_NULL;
4353           PetscInt closureSize, cl;
4354 
4355           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4356           for (cl = 0; cl < closureSize*2; cl += 2) {
4357             const PetscInt clp = closure[cl];
4358 
4359             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4360             if ((val >= 0) && (val < dim-1)) {
4361               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4362               break;
4363             }
4364           }
4365           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4366         }
4367       }
4368     }
4369   }
4370   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4371   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4372   /* Search for other cells/faces/edges connected to the fault by a vertex */
4373   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4374   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4375   if (!dimIS) PetscFunctionReturn(0);
4376   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4377   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4378   for (p = 0; p < numPoints; ++p) {
4379     PetscInt *star = PETSC_NULL;
4380     PetscInt starSize, s;
4381     PetscInt again = 1;  /* 0: Finished 1: Keep iterating after a change 2: No change */
4382 
4383     /* First mark cells connected to the fault */
4384     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4385     while (again) {
4386       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4387       again = 0;
4388       for (s = 0; s < starSize*2; s += 2) {
4389         const PetscInt point = star[s];
4390         const PetscInt *cone;
4391         PetscInt       coneSize, c;
4392 
4393         if ((point < cStart) || (point >= cEnd)) continue;
4394         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4395         if (val != -1) continue;
4396         again = 2;
4397         ierr  = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4398         ierr  = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4399         for (c = 0; c < coneSize; ++c) {
4400           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4401           if (val != -1) {
4402             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);
4403             if (val > 0) {
4404               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4405             } else {
4406               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4407             }
4408             again = 1;
4409             break;
4410           }
4411         }
4412       }
4413     }
4414     /* Classify the rest by cell membership */
4415     for (s = 0; s < starSize*2; s += 2) {
4416       const PetscInt point = star[s];
4417 
4418       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4419       if (val == -1) {
4420         PetscInt  *sstar = PETSC_NULL;
4421         PetscInt  sstarSize, ss;
4422         PetscBool marked = PETSC_FALSE;
4423 
4424         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4425         for (ss = 0; ss < sstarSize*2; ss += 2) {
4426           const PetscInt spoint = sstar[ss];
4427 
4428           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4429           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4430           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4431           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4432           if (val > 0) {
4433             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4434           } else {
4435             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4436           }
4437           marked = PETSC_TRUE;
4438           break;
4439         }
4440         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4441         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4442       }
4443     }
4444     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4445   }
4446   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4447   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4448   PetscFunctionReturn(0);
4449 }
4450 
4451 #undef __FUNCT__
4452 #define __FUNCT__ "DMPlexInterpolate_2D"
4453 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4454 {
4455   DM             idm;
4456   DM_Plex        *mesh;
4457   PetscHashIJ    edgeTable;
4458   PetscInt       *off;
4459   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4460   PetscInt       numEdges, firstEdge, edge, e;
4461   PetscErrorCode ierr;
4462 
4463   PetscFunctionBegin;
4464   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4465   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4466   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4467   numCells    = cEnd - cStart;
4468   numVertices = vEnd - vStart;
4469   firstEdge   = numCells + numVertices;
4470   numEdges    = 0;
4471   /* Count edges using algorithm from CreateNeighborCSR */
4472   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4473   if (off) {
4474     PetscInt numCorners = 0;
4475 
4476     numEdges = off[numCells]/2;
4477 #if 0
4478     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4479     numEdges += 3*numCells - off[numCells];
4480 #else
4481     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4482     for (c = cStart; c < cEnd; ++c) {
4483       PetscInt coneSize;
4484 
4485       ierr        = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4486       numCorners += coneSize;
4487     }
4488     numEdges += numCorners - off[numCells];
4489 #endif
4490   }
4491 #if 0
4492   /* Check Euler characteristic V - E + F = 1 */
4493   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4494 #endif
4495   /* Create interpolated mesh */
4496   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4497   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4498   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4499   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4500   for (c = 0; c < numCells; ++c) {
4501     PetscInt numCorners;
4502 
4503     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4504     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4505   }
4506   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4507     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4508   }
4509   ierr = DMSetUp(idm);CHKERRQ(ierr);
4510   /* Get edge cones from subsets of cell vertices */
4511   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4512   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4513 
4514   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4515     const PetscInt *cellFaces;
4516     PetscInt       numCellFaces, faceSize, cf;
4517 
4518     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4519     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4520     for (cf = 0; cf < numCellFaces; ++cf) {
4521 #if 1
4522       PetscHashIJKey key;
4523 
4524       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4525       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4526       ierr  = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4527       if (e < 0) {
4528         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4529         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4530         e    = edge++;
4531       }
4532 #else
4533       PetscBool found = PETSC_FALSE;
4534 
4535       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4536       for (e = firstEdge; e < edge; ++e) {
4537         const PetscInt *cone;
4538 
4539         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4540         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4541             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4542           found = PETSC_TRUE;
4543           break;
4544         }
4545       }
4546       if (!found) {
4547         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4548         ++edge;
4549       }
4550 #endif
4551       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4552     }
4553   }
4554   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4555   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4556   ierr = PetscFree(off);CHKERRQ(ierr);
4557   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4558   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4559   mesh = (DM_Plex*) (idm)->data;
4560   /* Orient edges */
4561   for (c = 0; c < numCells; ++c) {
4562     const PetscInt *cone = PETSC_NULL, *cellFaces;
4563     PetscInt       coneSize, coff, numCellFaces, faceSize, cf;
4564 
4565     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4566     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4567     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4568     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4569     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4570     for (cf = 0; cf < numCellFaces; ++cf) {
4571       const PetscInt *econe = PETSC_NULL;
4572       PetscInt       esize;
4573 
4574       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4575       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4576       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]);
4577       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4578         /* Correctly oriented */
4579         mesh->coneOrientations[coff+cf] = 0;
4580       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4581         /* Start at index 1, and reverse orientation */
4582         mesh->coneOrientations[coff+cf] = -(1+1);
4583       }
4584     }
4585   }
4586   *dmInt = idm;
4587   PetscFunctionReturn(0);
4588 }
4589 
4590 #undef __FUNCT__
4591 #define __FUNCT__ "DMPlexInterpolate_3D"
4592 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4593 {
4594   DM             idm, fdm;
4595   DM_Plex        *mesh;
4596   PetscInt       *off;
4597   const PetscInt numCorners = 4;
4598   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4599   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4600   PetscErrorCode ierr;
4601 
4602   PetscFunctionBegin;
4603   {
4604     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4605     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4606     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4607   }
4608   ierr        = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4609   ierr        = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4610   ierr        = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4611   numCells    = cEnd - cStart;
4612   numVertices = vEnd - vStart;
4613   firstFace   = numCells + numVertices;
4614   numFaces    = 0;
4615   /* Count faces using algorithm from CreateNeighborCSR */
4616   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4617   if (off) {
4618     numFaces = off[numCells]/2;
4619     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4620     numFaces += 4*numCells - off[numCells];
4621   }
4622   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4623   firstEdge = firstFace + numFaces;
4624   numEdges  = numVertices + numFaces - numCells - 1;
4625   /* Create interpolated mesh */
4626   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4627   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4628   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4629   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4630   for (c = 0; c < numCells; ++c) {
4631     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4632   }
4633   for (f = firstFace; f < firstFace+numFaces; ++f) {
4634     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4635   }
4636   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4637     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4638   }
4639   ierr = DMSetUp(idm);CHKERRQ(ierr);
4640   /* Get face cones from subsets of cell vertices */
4641   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4642   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4643   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4644   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4645   for (f = firstFace; f < firstFace+numFaces; ++f) {
4646     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4647   }
4648   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4649   for (c = 0, face = firstFace; c < numCells; ++c) {
4650     const PetscInt *cellFaces;
4651     PetscInt       numCellFaces, faceSize, cf;
4652 
4653     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4654     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4655     for (cf = 0; cf < numCellFaces; ++cf) {
4656       PetscBool found = PETSC_FALSE;
4657 
4658       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4659       for (f = firstFace; f < face; ++f) {
4660         const PetscInt *cone = PETSC_NULL;
4661 
4662         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4663         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4664             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4665             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4666             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4667             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4668             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4669           found = PETSC_TRUE;
4670           break;
4671         }
4672       }
4673       if (!found) {
4674         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4675         /* Save the vertices for orientation calculation */
4676         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4677         ++face;
4678       }
4679       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4680     }
4681   }
4682   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4683   /* Get edge cones from subsets of face vertices */
4684   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4685     const PetscInt *cellFaces;
4686     PetscInt       numCellFaces, faceSize, cf;
4687 
4688     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4689     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4690     for (cf = 0; cf < numCellFaces; ++cf) {
4691       PetscBool found = PETSC_FALSE;
4692 
4693       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4694       for (e = firstEdge; e < edge; ++e) {
4695         const PetscInt *cone = PETSC_NULL;
4696 
4697         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4698         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4699             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4700           found = PETSC_TRUE;
4701           break;
4702         }
4703       }
4704       if (!found) {
4705         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4706         ++edge;
4707       }
4708       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4709     }
4710   }
4711   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4712   ierr = PetscFree(off);CHKERRQ(ierr);
4713   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4714   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4715   mesh = (DM_Plex*) (idm)->data;
4716   /* Orient edges */
4717   for (f = firstFace; f < firstFace+numFaces; ++f) {
4718     const PetscInt *cone, *cellFaces;
4719     PetscInt       coneSize, coff, numCellFaces, faceSize, cf;
4720 
4721     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4722     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4723     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4724     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4725     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4726     for (cf = 0; cf < numCellFaces; ++cf) {
4727       const PetscInt *econe;
4728       PetscInt       esize;
4729 
4730       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4731       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4732       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]);
4733       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4734         /* Correctly oriented */
4735         mesh->coneOrientations[coff+cf] = 0;
4736       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4737         /* Start at index 1, and reverse orientation */
4738         mesh->coneOrientations[coff+cf] = -(1+1);
4739       }
4740     }
4741   }
4742   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4743   /* Orient faces */
4744   for (c = 0; c < numCells; ++c) {
4745     const PetscInt *cone, *cellFaces;
4746     PetscInt       coneSize, coff, numCellFaces, faceSize, cf;
4747 
4748     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4749     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4750     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4751     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4752     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4753     for (cf = 0; cf < numCellFaces; ++cf) {
4754       PetscInt *origClosure = PETSC_NULL, *closure;
4755       PetscInt closureSize, i;
4756 
4757       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4758       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4759       for (i = 4; i < 7; ++i) {
4760         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);
4761       }
4762       closure = &origClosure[4*2];
4763       /* Remember that this is the orientation for edges, not vertices */
4764       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4765         /* Correctly oriented */
4766         mesh->coneOrientations[coff+cf] = 0;
4767       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4768         /* Shifted by 1 */
4769         mesh->coneOrientations[coff+cf] = 1;
4770       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4771         /* Shifted by 2 */
4772         mesh->coneOrientations[coff+cf] = 2;
4773       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4774         /* Start at edge 1, and reverse orientation */
4775         mesh->coneOrientations[coff+cf] = -(1+1);
4776       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4777         /* Start at index 0, and reverse orientation */
4778         mesh->coneOrientations[coff+cf] = -(0+1);
4779       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4780         /* Start at index 2, and reverse orientation */
4781         mesh->coneOrientations[coff+cf] = -(2+1);
4782       } 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);
4783       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4784     }
4785   }
4786   {
4787     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4788     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4789     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4790   }
4791   *dmInt = idm;
4792   PetscFunctionReturn(0);
4793 }
4794 
4795 #undef __FUNCT__
4796 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4797 /*
4798   This takes as input the common mesh generator output, a list of the vertices for each cell
4799 */
4800 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4801 {
4802   PetscInt       *cone, c, p;
4803   PetscErrorCode ierr;
4804 
4805   PetscFunctionBegin;
4806   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4807   for (c = 0; c < numCells; ++c) {
4808     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4809   }
4810   ierr = DMSetUp(dm);CHKERRQ(ierr);
4811   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4812   for (c = 0; c < numCells; ++c) {
4813     for (p = 0; p < numCorners; ++p) {
4814       cone[p] = cells[c*numCorners+p]+numCells;
4815     }
4816     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4817   }
4818   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4819   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4820   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4821   PetscFunctionReturn(0);
4822 }
4823 
4824 #undef __FUNCT__
4825 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4826 /*
4827   This takes as input the coordinates for each vertex
4828 */
4829 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4830 {
4831   PetscSection   coordSection;
4832   Vec            coordinates;
4833   PetscScalar    *coords;
4834   PetscInt       coordSize, v, d;
4835   PetscErrorCode ierr;
4836 
4837   PetscFunctionBegin;
4838   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4839   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4840   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4841   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4842   for (v = numCells; v < numCells+numVertices; ++v) {
4843     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4844     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4845   }
4846   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4847   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4848   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4849   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4850   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4851   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4852   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4853   for (v = 0; v < numVertices; ++v) {
4854     for (d = 0; d < spaceDim; ++d) {
4855       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4856     }
4857   }
4858   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4859   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4860   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4861   PetscFunctionReturn(0);
4862 }
4863 
4864 #undef __FUNCT__
4865 #define __FUNCT__ "DMPlexCreateFromCellList"
4866 /*
4867   This takes as input the common mesh generator output, a list of the vertices for each cell
4868 */
4869 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4870 {
4871   PetscErrorCode ierr;
4872 
4873   PetscFunctionBegin;
4874   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4875   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4876   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4877   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4878   if (interpolate) {
4879     DM idm;
4880 
4881     switch (dim) {
4882     case 2:
4883       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4884     case 3:
4885       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4886     default:
4887       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4888     }
4889     ierr = DMDestroy(dm);CHKERRQ(ierr);
4890     *dm  = idm;
4891   }
4892   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4893   PetscFunctionReturn(0);
4894 }
4895 
4896 #if defined(PETSC_HAVE_TRIANGLE)
4897 #include <triangle.h>
4898 
4899 #undef __FUNCT__
4900 #define __FUNCT__ "InitInput_Triangle"
4901 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4902 {
4903   PetscFunctionBegin;
4904   inputCtx->numberofpoints             = 0;
4905   inputCtx->numberofpointattributes    = 0;
4906   inputCtx->pointlist                  = PETSC_NULL;
4907   inputCtx->pointattributelist         = PETSC_NULL;
4908   inputCtx->pointmarkerlist            = PETSC_NULL;
4909   inputCtx->numberofsegments           = 0;
4910   inputCtx->segmentlist                = PETSC_NULL;
4911   inputCtx->segmentmarkerlist          = PETSC_NULL;
4912   inputCtx->numberoftriangleattributes = 0;
4913   inputCtx->trianglelist               = PETSC_NULL;
4914   inputCtx->numberofholes              = 0;
4915   inputCtx->holelist                   = PETSC_NULL;
4916   inputCtx->numberofregions            = 0;
4917   inputCtx->regionlist                 = PETSC_NULL;
4918   PetscFunctionReturn(0);
4919 }
4920 
4921 #undef __FUNCT__
4922 #define __FUNCT__ "InitOutput_Triangle"
4923 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4924 {
4925   PetscFunctionBegin;
4926   outputCtx->numberofpoints        = 0;
4927   outputCtx->pointlist             = PETSC_NULL;
4928   outputCtx->pointattributelist    = PETSC_NULL;
4929   outputCtx->pointmarkerlist       = PETSC_NULL;
4930   outputCtx->numberoftriangles     = 0;
4931   outputCtx->trianglelist          = PETSC_NULL;
4932   outputCtx->triangleattributelist = PETSC_NULL;
4933   outputCtx->neighborlist          = PETSC_NULL;
4934   outputCtx->segmentlist           = PETSC_NULL;
4935   outputCtx->segmentmarkerlist     = PETSC_NULL;
4936   outputCtx->numberofedges         = 0;
4937   outputCtx->edgelist              = PETSC_NULL;
4938   outputCtx->edgemarkerlist        = PETSC_NULL;
4939   PetscFunctionReturn(0);
4940 }
4941 
4942 #undef __FUNCT__
4943 #define __FUNCT__ "FiniOutput_Triangle"
4944 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4945 {
4946   PetscFunctionBegin;
4947   free(outputCtx->pointmarkerlist);
4948   free(outputCtx->edgelist);
4949   free(outputCtx->edgemarkerlist);
4950   free(outputCtx->trianglelist);
4951   free(outputCtx->neighborlist);
4952   PetscFunctionReturn(0);
4953 }
4954 
4955 #undef __FUNCT__
4956 #define __FUNCT__ "DMPlexGenerate_Triangle"
4957 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4958 {
4959   MPI_Comm             comm             = ((PetscObject) boundary)->comm;
4960   PetscInt             dim              = 2;
4961   const PetscBool      createConvexHull = PETSC_FALSE;
4962   const PetscBool      constrained      = PETSC_FALSE;
4963   struct triangulateio in;
4964   struct triangulateio out;
4965   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4966   PetscMPIInt          rank;
4967   PetscErrorCode       ierr;
4968 
4969   PetscFunctionBegin;
4970   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4971   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4972   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4973   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4974 
4975   in.numberofpoints = vEnd - vStart;
4976   if (in.numberofpoints > 0) {
4977     PetscSection coordSection;
4978     Vec          coordinates;
4979     PetscScalar  *array;
4980 
4981     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4982     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4983     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4984     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4985     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4986     for (v = vStart; v < vEnd; ++v) {
4987       const PetscInt idx = v - vStart;
4988       PetscInt       off, d;
4989 
4990       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4991       for (d = 0; d < dim; ++d) {
4992         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4993       }
4994       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4995     }
4996     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4997   }
4998   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4999   in.numberofsegments = eEnd - eStart;
5000   if (in.numberofsegments > 0) {
5001     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
5002     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
5003     for (e = eStart; e < eEnd; ++e) {
5004       const PetscInt idx = e - eStart;
5005       const PetscInt *cone;
5006 
5007       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
5008 
5009       in.segmentlist[idx*2+0] = cone[0] - vStart;
5010       in.segmentlist[idx*2+1] = cone[1] - vStart;
5011 
5012       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5013     }
5014   }
5015 #if 0 /* Do not currently support holes */
5016   PetscReal *holeCoords;
5017   PetscInt  h, d;
5018 
5019   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5020   if (in.numberofholes > 0) {
5021     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5022     for (h = 0; h < in.numberofholes; ++h) {
5023       for (d = 0; d < dim; ++d) {
5024         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5025       }
5026     }
5027   }
5028 #endif
5029   if (!rank) {
5030     char args[32];
5031 
5032     /* Take away 'Q' for verbose output */
5033     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5034     if (createConvexHull) {
5035       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5036     }
5037     if (constrained) {
5038       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5039     }
5040     triangulate(args, &in, &out, PETSC_NULL);
5041   }
5042   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5043   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5044   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5045   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5046   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5047 
5048   {
5049     const PetscInt numCorners  = 3;
5050     const PetscInt numCells    = out.numberoftriangles;
5051     const PetscInt numVertices = out.numberofpoints;
5052     const int      *cells      = out.trianglelist;
5053     const double   *meshCoords = out.pointlist;
5054 
5055     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5056     /* Set labels */
5057     for (v = 0; v < numVertices; ++v) {
5058       if (out.pointmarkerlist[v]) {
5059         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5060       }
5061     }
5062     if (interpolate) {
5063       for (e = 0; e < out.numberofedges; e++) {
5064         if (out.edgemarkerlist[e]) {
5065           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5066           const PetscInt *edges;
5067           PetscInt       numEdges;
5068 
5069           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5070           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5071           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5072           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5073         }
5074       }
5075     }
5076     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5077   }
5078 #if 0 /* Do not currently support holes */
5079   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5080 #endif
5081   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5082   PetscFunctionReturn(0);
5083 }
5084 
5085 #undef __FUNCT__
5086 #define __FUNCT__ "DMPlexRefine_Triangle"
5087 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5088 {
5089   MPI_Comm             comm = ((PetscObject) dm)->comm;
5090   PetscInt             dim  = 2;
5091   struct triangulateio in;
5092   struct triangulateio out;
5093   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5094   PetscMPIInt          rank;
5095   PetscErrorCode       ierr;
5096 
5097   PetscFunctionBegin;
5098   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5099   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5100   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5101   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5102   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5103   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5104 
5105   in.numberofpoints = vEnd - vStart;
5106   if (in.numberofpoints > 0) {
5107     PetscSection coordSection;
5108     Vec          coordinates;
5109     PetscScalar  *array;
5110 
5111     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5112     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5113     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5114     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5115     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5116     for (v = vStart; v < vEnd; ++v) {
5117       const PetscInt idx = v - vStart;
5118       PetscInt       off, d;
5119 
5120       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5121       for (d = 0; d < dim; ++d) {
5122         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5123       }
5124       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5125     }
5126     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5127   }
5128   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5129 
5130   in.numberofcorners   = 3;
5131   in.numberoftriangles = cEnd - cStart;
5132 
5133   in.trianglearealist  = (double*) maxVolumes;
5134   if (in.numberoftriangles > 0) {
5135     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5136     for (c = cStart; c < cEnd; ++c) {
5137       const PetscInt idx      = c - cStart;
5138       PetscInt       *closure = PETSC_NULL;
5139       PetscInt       closureSize;
5140 
5141       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5142       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5143       for (v = 0; v < 3; ++v) {
5144         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5145       }
5146       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5147     }
5148   }
5149   /* TODO: Segment markers are missing on input */
5150 #if 0 /* Do not currently support holes */
5151   PetscReal *holeCoords;
5152   PetscInt  h, d;
5153 
5154   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5155   if (in.numberofholes > 0) {
5156     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5157     for (h = 0; h < in.numberofholes; ++h) {
5158       for (d = 0; d < dim; ++d) {
5159         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5160       }
5161     }
5162   }
5163 #endif
5164   if (!rank) {
5165     char args[32];
5166 
5167     /* Take away 'Q' for verbose output */
5168     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5169     triangulate(args, &in, &out, PETSC_NULL);
5170   }
5171   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5172   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5173   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5174   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5175   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5176 
5177   {
5178     const PetscInt numCorners  = 3;
5179     const PetscInt numCells    = out.numberoftriangles;
5180     const PetscInt numVertices = out.numberofpoints;
5181     const int      *cells      = out.trianglelist;
5182     const double   *meshCoords = out.pointlist;
5183     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5184 
5185     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5186     /* Set labels */
5187     for (v = 0; v < numVertices; ++v) {
5188       if (out.pointmarkerlist[v]) {
5189         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5190       }
5191     }
5192     if (interpolate) {
5193       PetscInt e;
5194 
5195       for (e = 0; e < out.numberofedges; e++) {
5196         if (out.edgemarkerlist[e]) {
5197           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5198           const PetscInt *edges;
5199           PetscInt       numEdges;
5200 
5201           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5202           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5203           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5204           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5205         }
5206       }
5207     }
5208     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5209   }
5210 #if 0 /* Do not currently support holes */
5211   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5212 #endif
5213   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5214   PetscFunctionReturn(0);
5215 }
5216 #endif
5217 
5218 #if defined(PETSC_HAVE_TETGEN)
5219 #include <tetgen.h>
5220 #undef __FUNCT__
5221 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5222 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5223 {
5224   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5225   const PetscInt dim  = 3;
5226   ::tetgenio     in;
5227   ::tetgenio     out;
5228   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5229   PetscMPIInt    rank;
5230   PetscErrorCode ierr;
5231 
5232   PetscFunctionBegin;
5233   ierr              = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5234   ierr              = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5235   in.numberofpoints = vEnd - vStart;
5236   if (in.numberofpoints > 0) {
5237     PetscSection coordSection;
5238     Vec          coordinates;
5239     PetscScalar  *array;
5240 
5241     in.pointlist       = new double[in.numberofpoints*dim];
5242     in.pointmarkerlist = new int[in.numberofpoints];
5243 
5244     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5245     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5246     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5247     for (v = vStart; v < vEnd; ++v) {
5248       const PetscInt idx = v - vStart;
5249       PetscInt       off, d;
5250 
5251       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5252       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5253       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5254     }
5255     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5256   }
5257   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5258 
5259   in.numberoffacets = fEnd - fStart;
5260   if (in.numberoffacets > 0) {
5261     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5262     in.facetmarkerlist = new int[in.numberoffacets];
5263     for (f = fStart; f < fEnd; ++f) {
5264       const PetscInt idx     = f - fStart;
5265       PetscInt       *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5266 
5267       in.facetlist[idx].numberofpolygons = 1;
5268       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5269       in.facetlist[idx].numberofholes    = 0;
5270       in.facetlist[idx].holelist         = NULL;
5271 
5272       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5273       for (p = 0; p < numPoints*2; p += 2) {
5274         const PetscInt point = points[p];
5275         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5276       }
5277 
5278       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5279       poly->numberofvertices = numVertices;
5280       poly->vertexlist       = new int[poly->numberofvertices];
5281       for (v = 0; v < numVertices; ++v) {
5282         const PetscInt vIdx = points[v] - vStart;
5283         poly->vertexlist[v] = vIdx;
5284       }
5285       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5286       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5287     }
5288   }
5289   if (!rank) {
5290     char args[32];
5291 
5292     /* Take away 'Q' for verbose output */
5293     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5294     ::tetrahedralize(args, &in, &out);
5295   }
5296   {
5297     const PetscInt numCorners  = 4;
5298     const PetscInt numCells    = out.numberoftetrahedra;
5299     const PetscInt numVertices = out.numberofpoints;
5300     const int      *cells      = out.tetrahedronlist;
5301     const double   *meshCoords = out.pointlist;
5302 
5303     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5304     /* Set labels */
5305     for (v = 0; v < numVertices; ++v) {
5306       if (out.pointmarkerlist[v]) {
5307         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5308       }
5309     }
5310     if (interpolate) {
5311       PetscInt e;
5312 
5313       for (e = 0; e < out.numberofedges; e++) {
5314         if (out.edgemarkerlist[e]) {
5315           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5316           const PetscInt *edges;
5317           PetscInt       numEdges;
5318 
5319           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5320           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5321           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5322           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5323         }
5324       }
5325       for (f = 0; f < out.numberoftrifaces; f++) {
5326         if (out.trifacemarkerlist[f]) {
5327           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5328           const PetscInt *faces;
5329           PetscInt       numFaces;
5330 
5331           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5332           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5333           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5334           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5335         }
5336       }
5337     }
5338     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5339   }
5340   PetscFunctionReturn(0);
5341 }
5342 
5343 #undef __FUNCT__
5344 #define __FUNCT__ "DMPlexRefine_Tetgen"
5345 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5346 {
5347   MPI_Comm       comm = ((PetscObject) dm)->comm;
5348   const PetscInt dim  = 3;
5349   ::tetgenio     in;
5350   ::tetgenio     out;
5351   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5352   PetscMPIInt    rank;
5353   PetscErrorCode ierr;
5354 
5355   PetscFunctionBegin;
5356   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5357   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5358   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5359   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5360 
5361   in.numberofpoints = vEnd - vStart;
5362   if (in.numberofpoints > 0) {
5363     PetscSection coordSection;
5364     Vec          coordinates;
5365     PetscScalar  *array;
5366 
5367     in.pointlist       = new double[in.numberofpoints*dim];
5368     in.pointmarkerlist = new int[in.numberofpoints];
5369 
5370     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5371     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5372     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5373     for (v = vStart; v < vEnd; ++v) {
5374       const PetscInt idx = v - vStart;
5375       PetscInt       off, d;
5376 
5377       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5378       for (d = 0; d < dim; ++d) in.pointlist[idx*dim + d] = array[off+d];
5379       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5380     }
5381     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5382   }
5383   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5384 
5385   in.numberofcorners       = 4;
5386   in.numberoftetrahedra    = cEnd - cStart;
5387   in.tetrahedronvolumelist = (double*) maxVolumes;
5388   if (in.numberoftetrahedra > 0) {
5389     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5390     for (c = cStart; c < cEnd; ++c) {
5391       const PetscInt idx      = c - cStart;
5392       PetscInt       *closure = PETSC_NULL;
5393       PetscInt       closureSize;
5394 
5395       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5396       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5397       for (v = 0; v < 4; ++v) {
5398         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5399       }
5400       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5401     }
5402   }
5403   /* TODO: Put in boundary faces with markers */
5404   if (!rank) {
5405     char args[32];
5406 
5407     /* Take away 'Q' for verbose output */
5408     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5409     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5410     ::tetrahedralize(args, &in, &out);
5411   }
5412   in.tetrahedronvolumelist = NULL;
5413 
5414   {
5415     const PetscInt numCorners  = 4;
5416     const PetscInt numCells    = out.numberoftetrahedra;
5417     const PetscInt numVertices = out.numberofpoints;
5418     const int      *cells      = out.tetrahedronlist;
5419     const double   *meshCoords = out.pointlist;
5420     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5421 
5422     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5423     /* Set labels */
5424     for (v = 0; v < numVertices; ++v) {
5425       if (out.pointmarkerlist[v]) {
5426         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5427       }
5428     }
5429     if (interpolate) {
5430       PetscInt e, f;
5431 
5432       for (e = 0; e < out.numberofedges; e++) {
5433         if (out.edgemarkerlist[e]) {
5434           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5435           const PetscInt *edges;
5436           PetscInt       numEdges;
5437 
5438           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5439           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5440           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5441           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5442         }
5443       }
5444       for (f = 0; f < out.numberoftrifaces; f++) {
5445         if (out.trifacemarkerlist[f]) {
5446           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5447           const PetscInt *faces;
5448           PetscInt       numFaces;
5449 
5450           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5451           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5452           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5453           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5454         }
5455       }
5456     }
5457     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5458   }
5459   PetscFunctionReturn(0);
5460 }
5461 #endif
5462 
5463 #if defined(PETSC_HAVE_CTETGEN)
5464 #include "ctetgen.h"
5465 
5466 #undef __FUNCT__
5467 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5468 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5469 {
5470   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5471   const PetscInt dim  = 3;
5472   PLC            *in, *out;
5473   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5474   PetscMPIInt    rank;
5475   PetscErrorCode ierr;
5476 
5477   PetscFunctionBegin;
5478   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5479   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5480   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5481   ierr = PLCCreate(&in);CHKERRQ(ierr);
5482   ierr = PLCCreate(&out);CHKERRQ(ierr);
5483 
5484   in->numberofpoints = vEnd - vStart;
5485   if (in->numberofpoints > 0) {
5486     PetscSection coordSection;
5487     Vec          coordinates;
5488     PetscScalar  *array;
5489 
5490     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5491     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5492     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5493     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5494     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5495     for (v = vStart; v < vEnd; ++v) {
5496       const PetscInt idx = v - vStart;
5497       PetscInt       off, d, m;
5498 
5499       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5500       for (d = 0; d < dim; ++d) {
5501         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5502       }
5503       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5504 
5505       in->pointmarkerlist[idx] = (int) m;
5506     }
5507     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5508   }
5509   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5510 
5511   in->numberoffacets = fEnd - fStart;
5512   if (in->numberoffacets > 0) {
5513     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5514     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5515     for (f = fStart; f < fEnd; ++f) {
5516       const PetscInt idx     = f - fStart;
5517       PetscInt       *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5518       polygon        *poly;
5519 
5520       in->facetlist[idx].numberofpolygons = 1;
5521 
5522       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5523 
5524       in->facetlist[idx].numberofholes    = 0;
5525       in->facetlist[idx].holelist         = PETSC_NULL;
5526 
5527       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5528       for (p = 0; p < numPoints*2; p += 2) {
5529         const PetscInt point = points[p];
5530         if ((point >= vStart) && (point < vEnd)) points[numVertices++] = point;
5531       }
5532 
5533       poly                   = in->facetlist[idx].polygonlist;
5534       poly->numberofvertices = numVertices;
5535       ierr                   = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5536       for (v = 0; v < numVertices; ++v) {
5537         const PetscInt vIdx = points[v] - vStart;
5538         poly->vertexlist[v] = vIdx;
5539       }
5540       ierr                     = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5541       in->facetmarkerlist[idx] = (int) m;
5542       ierr                     = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5543     }
5544   }
5545   if (!rank) {
5546     TetGenOpts t;
5547 
5548     ierr        = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5549     t.in        = boundary; /* Should go away */
5550     t.plc       = 1;
5551     t.quality   = 1;
5552     t.edgesout  = 1;
5553     t.zeroindex = 1;
5554     t.quiet     = 1;
5555     t.verbose   = verbose;
5556     ierr        = TetGenCheckOpts(&t);CHKERRQ(ierr);
5557     ierr        = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5558   }
5559   {
5560     const PetscInt numCorners  = 4;
5561     const PetscInt numCells    = out->numberoftetrahedra;
5562     const PetscInt numVertices = out->numberofpoints;
5563     const int      *cells      = out->tetrahedronlist;
5564     const double   *meshCoords = out->pointlist;
5565 
5566     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5567     /* Set labels */
5568     for (v = 0; v < numVertices; ++v) {
5569       if (out->pointmarkerlist[v]) {
5570         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5571       }
5572     }
5573     if (interpolate) {
5574       PetscInt e;
5575 
5576       for (e = 0; e < out->numberofedges; e++) {
5577         if (out->edgemarkerlist[e]) {
5578           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5579           const PetscInt *edges;
5580           PetscInt       numEdges;
5581 
5582           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5583           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5584           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5585           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5586         }
5587       }
5588       for (f = 0; f < out->numberoftrifaces; f++) {
5589         if (out->trifacemarkerlist[f]) {
5590           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5591           const PetscInt *faces;
5592           PetscInt       numFaces;
5593 
5594           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5595           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5596           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5597           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5598         }
5599       }
5600     }
5601     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5602   }
5603 
5604   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5605   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5606   PetscFunctionReturn(0);
5607 }
5608 
5609 #undef __FUNCT__
5610 #define __FUNCT__ "DMPlexRefine_CTetgen"
5611 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5612 {
5613   MPI_Comm       comm = ((PetscObject) dm)->comm;
5614   const PetscInt dim  = 3;
5615   PLC            *in, *out;
5616   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5617   PetscMPIInt    rank;
5618   PetscErrorCode ierr;
5619 
5620   PetscFunctionBegin;
5621   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5622   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5623   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5624   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5625   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5626   ierr = PLCCreate(&in);CHKERRQ(ierr);
5627   ierr = PLCCreate(&out);CHKERRQ(ierr);
5628 
5629   in->numberofpoints = vEnd - vStart;
5630   if (in->numberofpoints > 0) {
5631     PetscSection coordSection;
5632     Vec          coordinates;
5633     PetscScalar  *array;
5634 
5635     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5636     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5637     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5638     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5639     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5640     for (v = vStart; v < vEnd; ++v) {
5641       const PetscInt idx = v - vStart;
5642       PetscInt       off, d, m;
5643 
5644       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5645       for (d = 0; d < dim; ++d) {
5646         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5647       }
5648       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5649 
5650       in->pointmarkerlist[idx] = (int) m;
5651     }
5652     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5653   }
5654   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5655 
5656   in->numberofcorners       = 4;
5657   in->numberoftetrahedra    = cEnd - cStart;
5658   in->tetrahedronvolumelist = maxVolumes;
5659   if (in->numberoftetrahedra > 0) {
5660     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5661     for (c = cStart; c < cEnd; ++c) {
5662       const PetscInt idx      = c - cStart;
5663       PetscInt       *closure = PETSC_NULL;
5664       PetscInt       closureSize;
5665 
5666       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5667       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5668       for (v = 0; v < 4; ++v) {
5669         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5670       }
5671       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5672     }
5673   }
5674   if (!rank) {
5675     TetGenOpts t;
5676 
5677     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5678 
5679     t.in        = dm; /* Should go away */
5680     t.refine    = 1;
5681     t.varvolume = 1;
5682     t.quality   = 1;
5683     t.edgesout  = 1;
5684     t.zeroindex = 1;
5685     t.quiet     = 1;
5686     t.verbose   = verbose; /* Change this */
5687 
5688     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5689     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5690   }
5691   {
5692     const PetscInt numCorners  = 4;
5693     const PetscInt numCells    = out->numberoftetrahedra;
5694     const PetscInt numVertices = out->numberofpoints;
5695     const int      *cells      = out->tetrahedronlist;
5696     const double   *meshCoords = out->pointlist;
5697     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5698 
5699     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5700     /* Set labels */
5701     for (v = 0; v < numVertices; ++v) {
5702       if (out->pointmarkerlist[v]) {
5703         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5704       }
5705     }
5706     if (interpolate) {
5707       PetscInt e, f;
5708 
5709       for (e = 0; e < out->numberofedges; e++) {
5710         if (out->edgemarkerlist[e]) {
5711           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5712           const PetscInt *edges;
5713           PetscInt       numEdges;
5714 
5715           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5716           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5717           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5718           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5719         }
5720       }
5721       for (f = 0; f < out->numberoftrifaces; f++) {
5722         if (out->trifacemarkerlist[f]) {
5723           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5724           const PetscInt *faces;
5725           PetscInt       numFaces;
5726 
5727           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5728           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5729           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5730           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5731         }
5732       }
5733     }
5734     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5735   }
5736   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5737   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5738   PetscFunctionReturn(0);
5739 }
5740 #endif
5741 
5742 #undef __FUNCT__
5743 #define __FUNCT__ "DMPlexGenerate"
5744 /*@C
5745   DMPlexGenerate - Generates a mesh.
5746 
5747   Not Collective
5748 
5749   Input Parameters:
5750 + boundary - The DMPlex boundary object
5751 . name - The mesh generation package name
5752 - interpolate - Flag to create intermediate mesh elements
5753 
5754   Output Parameter:
5755 . mesh - The DMPlex object
5756 
5757   Level: intermediate
5758 
5759 .keywords: mesh, elements
5760 .seealso: DMPlexCreate(), DMRefine()
5761 @*/
5762 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5763 {
5764   PetscInt       dim;
5765   char           genname[1024];
5766   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5767   PetscErrorCode ierr;
5768 
5769   PetscFunctionBegin;
5770   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5771   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5772   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5773   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5774   if (flg) name = genname;
5775   if (name) {
5776     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5777     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5778     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5779   }
5780   switch (dim) {
5781   case 1:
5782     if (!name || isTriangle) {
5783 #if defined(PETSC_HAVE_TRIANGLE)
5784       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5785 #else
5786       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5787 #endif
5788     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5789     break;
5790   case 2:
5791     if (!name || isCTetgen) {
5792 #if defined(PETSC_HAVE_CTETGEN)
5793       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5794 #else
5795       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5796 #endif
5797     } else if (isTetgen) {
5798 #if defined(PETSC_HAVE_TETGEN)
5799       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5800 #else
5801       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5802 #endif
5803     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5804     break;
5805   default:
5806     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5807   }
5808   PetscFunctionReturn(0);
5809 }
5810 
5811 typedef PetscInt CellRefiner;
5812 
5813 #undef __FUNCT__
5814 #define __FUNCT__ "GetDepthStart_Private"
5815 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5816 {
5817   PetscFunctionBegin;
5818   if (cStart) *cStart = 0;
5819   if (vStart) *vStart = depthSize[depth];
5820   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5821   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5822   PetscFunctionReturn(0);
5823 }
5824 
5825 #undef __FUNCT__
5826 #define __FUNCT__ "GetDepthEnd_Private"
5827 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5828 {
5829   PetscFunctionBegin;
5830   if (cEnd) *cEnd = depthSize[depth];
5831   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5832   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5833   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5834   PetscFunctionReturn(0);
5835 }
5836 
5837 #undef __FUNCT__
5838 #define __FUNCT__ "CellRefinerGetSizes"
5839 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5840 {
5841   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5842   PetscErrorCode ierr;
5843 
5844   PetscFunctionBegin;
5845   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5846   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5847   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5848   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5849   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5850   switch (refiner) {
5851   case 1:
5852     /* Simplicial 2D */
5853     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5854     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5855     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5856     break;
5857   case 3:
5858     /* Hybrid 2D */
5859     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5860     cMax = PetscMin(cEnd, cMax);
5861     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5862     fMax         = PetscMin(fEnd, fMax);
5863     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5864     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 */
5865     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5866     break;
5867   case 2:
5868     /* Hex 2D */
5869     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5870     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5871     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5872     break;
5873   default:
5874     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5875   }
5876   PetscFunctionReturn(0);
5877 }
5878 
5879 #undef __FUNCT__
5880 #define __FUNCT__ "CellRefinerSetConeSizes"
5881 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5882 {
5883   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5884   PetscErrorCode ierr;
5885 
5886   PetscFunctionBegin;
5887   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5888   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5889   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5890   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5891   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5892   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5893   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5894   switch (refiner) {
5895   case 1:
5896     /* Simplicial 2D */
5897     /* All cells have 3 faces */
5898     for (c = cStart; c < cEnd; ++c) {
5899       for (r = 0; r < 4; ++r) {
5900         const PetscInt newp = (c - cStart)*4 + r;
5901 
5902         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5903       }
5904     }
5905     /* Split faces have 2 vertices and the same cells as the parent */
5906     for (f = fStart; f < fEnd; ++f) {
5907       for (r = 0; r < 2; ++r) {
5908         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5909         PetscInt       size;
5910 
5911         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5912         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5913         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5914       }
5915     }
5916     /* Interior faces have 2 vertices and 2 cells */
5917     for (c = cStart; c < cEnd; ++c) {
5918       for (r = 0; r < 3; ++r) {
5919         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5920 
5921         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5922         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5923       }
5924     }
5925     /* Old vertices have identical supports */
5926     for (v = vStart; v < vEnd; ++v) {
5927       const PetscInt newp = vStartNew + (v - vStart);
5928       PetscInt       size;
5929 
5930       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5931       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5932     }
5933     /* Face vertices have 2 + cells*2 supports */
5934     for (f = fStart; f < fEnd; ++f) {
5935       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5936       PetscInt       size;
5937 
5938       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5939       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5940     }
5941     break;
5942   case 2:
5943     /* Hex 2D */
5944     /* All cells have 4 faces */
5945     for (c = cStart; c < cEnd; ++c) {
5946       for (r = 0; r < 4; ++r) {
5947         const PetscInt newp = (c - cStart)*4 + r;
5948 
5949         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5950       }
5951     }
5952     /* Split faces have 2 vertices and the same cells as the parent */
5953     for (f = fStart; f < fEnd; ++f) {
5954       for (r = 0; r < 2; ++r) {
5955         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5956         PetscInt       size;
5957 
5958         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5959         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5960         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5961       }
5962     }
5963     /* Interior faces have 2 vertices and 2 cells */
5964     for (c = cStart; c < cEnd; ++c) {
5965       for (r = 0; r < 4; ++r) {
5966         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5967 
5968         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5969         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5970       }
5971     }
5972     /* Old vertices have identical supports */
5973     for (v = vStart; v < vEnd; ++v) {
5974       const PetscInt newp = vStartNew + (v - vStart);
5975       PetscInt       size;
5976 
5977       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5978       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5979     }
5980     /* Face vertices have 2 + cells supports */
5981     for (f = fStart; f < fEnd; ++f) {
5982       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5983       PetscInt       size;
5984 
5985       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5986       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5987     }
5988     /* Cell vertices have 4 supports */
5989     for (c = cStart; c < cEnd; ++c) {
5990       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5991 
5992       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5993     }
5994     break;
5995   case 3:
5996     /* Hybrid 2D */
5997     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5998     cMax = PetscMin(cEnd, cMax);
5999     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6000     fMax = PetscMin(fEnd, fMax);
6001     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
6002     /* Interior cells have 3 faces */
6003     for (c = cStart; c < cMax; ++c) {
6004       for (r = 0; r < 4; ++r) {
6005         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
6006 
6007         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
6008       }
6009     }
6010     /* Hybrid cells have 4 faces */
6011     for (c = cMax; c < cEnd; ++c) {
6012       for (r = 0; r < 2; ++r) {
6013         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
6014 
6015         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
6016       }
6017     }
6018     /* Interior split faces have 2 vertices and the same cells as the parent */
6019     for (f = fStart; f < fMax; ++f) {
6020       for (r = 0; r < 2; ++r) {
6021         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6022         PetscInt       size;
6023 
6024         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6025         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6026         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6027       }
6028     }
6029     /* Interior cell faces have 2 vertices and 2 cells */
6030     for (c = cStart; c < cMax; ++c) {
6031       for (r = 0; r < 3; ++r) {
6032         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6033 
6034         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6035         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6036       }
6037     }
6038     /* Hybrid faces have 2 vertices and the same cells */
6039     for (f = fMax; f < fEnd; ++f) {
6040       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6041       PetscInt       size;
6042 
6043       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6044       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6045       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6046     }
6047     /* Hybrid cell faces have 2 vertices and 2 cells */
6048     for (c = cMax; c < cEnd; ++c) {
6049       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6050 
6051       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6052       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6053     }
6054     /* Old vertices have identical supports */
6055     for (v = vStart; v < vEnd; ++v) {
6056       const PetscInt newp = vStartNew + (v - vStart);
6057       PetscInt       size;
6058 
6059       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6060       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6061     }
6062     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6063     for (f = fStart; f < fMax; ++f) {
6064       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6065       const PetscInt *support;
6066       PetscInt       size, newSize = 2, s;
6067 
6068       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6069       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6070       for (s = 0; s < size; ++s) {
6071         if (support[s] >= cMax) newSize += 1;
6072         else newSize += 2;
6073       }
6074       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6075     }
6076     break;
6077   default:
6078     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6079   }
6080   PetscFunctionReturn(0);
6081 }
6082 
6083 #undef __FUNCT__
6084 #define __FUNCT__ "CellRefinerSetCones"
6085 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6086 {
6087   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;
6088   PetscInt       maxSupportSize, *supportRef;
6089   PetscErrorCode ierr;
6090 
6091   PetscFunctionBegin;
6092   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6093   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6094   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6095   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6096   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6097   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6098   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6099   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6100   switch (refiner) {
6101   case 1:
6102     /* Simplicial 2D */
6103     /*
6104      2
6105      |\
6106      | \
6107      |  \
6108      |   \
6109      | C  \
6110      |     \
6111      |      \
6112      2---1---1
6113      |\  D  / \
6114      | 2   0   \
6115      |A \ /  B  \
6116      0---0-------1
6117      */
6118     /* All cells have 3 faces */
6119     for (c = cStart; c < cEnd; ++c) {
6120       const PetscInt newp = cStartNew + (c - cStart)*4;
6121       const PetscInt *cone, *ornt;
6122       PetscInt       coneNew[3], orntNew[3];
6123 
6124       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6125       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6126       /* A triangle */
6127       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6128       orntNew[0] = ornt[0];
6129       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6130       orntNew[1] = -2;
6131       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6132       orntNew[2] = ornt[2];
6133       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6134       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6135 #if 1
6136       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);
6137       for (p = 0; p < 3; ++p) {
6138         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);
6139       }
6140 #endif
6141       /* B triangle */
6142       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6143       orntNew[0] = ornt[0];
6144       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6145       orntNew[1] = ornt[1];
6146       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6147       orntNew[2] = -2;
6148       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6149       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6150 #if 1
6151       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);
6152       for (p = 0; p < 3; ++p) {
6153         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);
6154       }
6155 #endif
6156       /* C triangle */
6157       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6158       orntNew[0] = -2;
6159       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6160       orntNew[1] = ornt[1];
6161       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6162       orntNew[2] = ornt[2];
6163       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6164       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6165 #if 1
6166       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);
6167       for (p = 0; p < 3; ++p) {
6168         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);
6169       }
6170 #endif
6171       /* D triangle */
6172       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6173       orntNew[0] = 0;
6174       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6175       orntNew[1] = 0;
6176       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6177       orntNew[2] = 0;
6178       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6179       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6180 #if 1
6181       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);
6182       for (p = 0; p < 3; ++p) {
6183         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);
6184       }
6185 #endif
6186     }
6187     /* Split faces have 2 vertices and the same cells as the parent */
6188     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6189     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6190     for (f = fStart; f < fEnd; ++f) {
6191       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6192 
6193       for (r = 0; r < 2; ++r) {
6194         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6195         const PetscInt *cone, *support;
6196         PetscInt       coneNew[2], coneSize, c, supportSize, s;
6197 
6198         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6199         coneNew[0]       = vStartNew + (cone[0] - vStart);
6200         coneNew[1]       = vStartNew + (cone[1] - vStart);
6201         coneNew[(r+1)%2] = newv;
6202         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6203 #if 1
6204         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6205         for (p = 0; p < 2; ++p) {
6206           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);
6207         }
6208 #endif
6209         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6210         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6211         for (s = 0; s < supportSize; ++s) {
6212           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6213           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6214           for (c = 0; c < coneSize; ++c) {
6215             if (cone[c] == f) break;
6216           }
6217           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6218         }
6219         ierr = DMPlexSetSupport(rdm, newp, supportRef);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 < supportSize; ++p) {
6223           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);
6224         }
6225 #endif
6226       }
6227     }
6228     /* Interior faces have 2 vertices and 2 cells */
6229     for (c = cStart; c < cEnd; ++c) {
6230       const PetscInt *cone;
6231 
6232       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6233       for (r = 0; r < 3; ++r) {
6234         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6235         PetscInt       coneNew[2];
6236         PetscInt       supportNew[2];
6237 
6238         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6239         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6240         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6241 #if 1
6242         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6243         for (p = 0; p < 2; ++p) {
6244           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);
6245         }
6246 #endif
6247         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6248         supportNew[1] = (c - cStart)*4 + 3;
6249         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6250 #if 1
6251         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6252         for (p = 0; p < 2; ++p) {
6253           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);
6254         }
6255 #endif
6256       }
6257     }
6258     /* Old vertices have identical supports */
6259     for (v = vStart; v < vEnd; ++v) {
6260       const PetscInt newp = vStartNew + (v - vStart);
6261       const PetscInt *support, *cone;
6262       PetscInt       size, s;
6263 
6264       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6265       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6266       for (s = 0; s < size; ++s) {
6267         PetscInt r = 0;
6268 
6269         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6270         if (cone[1] == v) r = 1;
6271         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6272       }
6273       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6274 #if 1
6275       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6276       for (p = 0; p < size; ++p) {
6277         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);
6278       }
6279 #endif
6280     }
6281     /* Face vertices have 2 + cells*2 supports */
6282     for (f = fStart; f < fEnd; ++f) {
6283       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6284       const PetscInt *cone, *support;
6285       PetscInt       size, s;
6286 
6287       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6288       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6289       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6290       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6291       for (s = 0; s < size; ++s) {
6292         PetscInt r = 0;
6293 
6294         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6295         if      (cone[1] == f) r = 1;
6296         else if (cone[2] == f) r = 2;
6297         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6298         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6299       }
6300       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6301 #if 1
6302       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6303       for (p = 0; p < 2+size*2; ++p) {
6304         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);
6305       }
6306 #endif
6307     }
6308     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6309     break;
6310   case 2:
6311     /* Hex 2D */
6312     /*
6313      3---------2---------2
6314      |         |         |
6315      |    D    2    C    |
6316      |         |         |
6317      3----3----0----1----1
6318      |         |         |
6319      |    A    0    B    |
6320      |         |         |
6321      0---------0---------1
6322      */
6323     /* All cells have 4 faces */
6324     for (c = cStart; c < cEnd; ++c) {
6325       const PetscInt newp = (c - cStart)*4;
6326       const PetscInt *cone, *ornt;
6327       PetscInt       coneNew[4], orntNew[4];
6328 
6329       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6330       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6331       /* A quad */
6332       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6333       orntNew[0] = ornt[0];
6334       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6335       orntNew[1] = 0;
6336       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6337       orntNew[2] = -2;
6338       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6339       orntNew[3] = ornt[3];
6340       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6341       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6342 #if 1
6343       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);
6344       for (p = 0; p < 4; ++p) {
6345         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6346       }
6347 #endif
6348       /* B quad */
6349       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6350       orntNew[0] = ornt[0];
6351       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6352       orntNew[1] = ornt[1];
6353       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6354       orntNew[2] = 0;
6355       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6356       orntNew[3] = -2;
6357       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6358       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6359 #if 1
6360       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);
6361       for (p = 0; p < 4; ++p) {
6362         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6363       }
6364 #endif
6365       /* C quad */
6366       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6367       orntNew[0] = -2;
6368       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6369       orntNew[1] = ornt[1];
6370       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6371       orntNew[2] = ornt[2];
6372       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6373       orntNew[3] = 0;
6374       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6375       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6376 #if 1
6377       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);
6378       for (p = 0; p < 4; ++p) {
6379         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6380       }
6381 #endif
6382       /* D quad */
6383       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6384       orntNew[0] = 0;
6385       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6386       orntNew[1] = -2;
6387       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6388       orntNew[2] = ornt[2];
6389       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6390       orntNew[3] = ornt[3];
6391       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6392       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6393 #if 1
6394       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);
6395       for (p = 0; p < 4; ++p) {
6396         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);
6397       }
6398 #endif
6399     }
6400     /* Split faces have 2 vertices and the same cells as the parent */
6401     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6402     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6403     for (f = fStart; f < fEnd; ++f) {
6404       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6405 
6406       for (r = 0; r < 2; ++r) {
6407         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6408         const PetscInt *cone, *support;
6409         PetscInt       coneNew[2], coneSize, c, supportSize, s;
6410 
6411         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6412         coneNew[0]       = vStartNew + (cone[0] - vStart);
6413         coneNew[1]       = vStartNew + (cone[1] - vStart);
6414         coneNew[(r+1)%2] = newv;
6415         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6416 #if 1
6417         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6418         for (p = 0; p < 2; ++p) {
6419           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);
6420         }
6421 #endif
6422         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6423         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6424         for (s = 0; s < supportSize; ++s) {
6425           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6426           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6427           for (c = 0; c < coneSize; ++c) {
6428             if (cone[c] == f) break;
6429           }
6430           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6431         }
6432         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6433 #if 1
6434         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6435         for (p = 0; p < supportSize; ++p) {
6436           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);
6437         }
6438 #endif
6439       }
6440     }
6441     /* Interior faces have 2 vertices and 2 cells */
6442     for (c = cStart; c < cEnd; ++c) {
6443       const PetscInt *cone;
6444       PetscInt       coneNew[2], supportNew[2];
6445 
6446       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6447       for (r = 0; r < 4; ++r) {
6448         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6449 
6450         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6451         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6452         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6453 #if 1
6454         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6455         for (p = 0; p < 2; ++p) {
6456           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);
6457         }
6458 #endif
6459         supportNew[0] = (c - cStart)*4 + r;
6460         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6461         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6462 #if 1
6463         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6464         for (p = 0; p < 2; ++p) {
6465           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);
6466         }
6467 #endif
6468       }
6469     }
6470     /* Old vertices have identical supports */
6471     for (v = vStart; v < vEnd; ++v) {
6472       const PetscInt newp = vStartNew + (v - vStart);
6473       const PetscInt *support, *cone;
6474       PetscInt       size, s;
6475 
6476       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6477       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6478       for (s = 0; s < size; ++s) {
6479         PetscInt r = 0;
6480 
6481         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6482         if (cone[1] == v) r = 1;
6483         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6484       }
6485       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6486 #if 1
6487       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6488       for (p = 0; p < size; ++p) {
6489         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);
6490       }
6491 #endif
6492     }
6493     /* Face vertices have 2 + cells supports */
6494     for (f = fStart; f < fEnd; ++f) {
6495       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6496       const PetscInt *cone, *support;
6497       PetscInt       size, s;
6498 
6499       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6500       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6501       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6502       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6503       for (s = 0; s < size; ++s) {
6504         PetscInt r = 0;
6505 
6506         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6507         if      (cone[1] == f) r = 1;
6508         else if (cone[2] == f) r = 2;
6509         else if (cone[3] == f) r = 3;
6510         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6511       }
6512       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6513 #if 1
6514       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6515       for (p = 0; p < 2+size; ++p) {
6516         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);
6517       }
6518 #endif
6519     }
6520     /* Cell vertices have 4 supports */
6521     for (c = cStart; c < cEnd; ++c) {
6522       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6523       PetscInt       supportNew[4];
6524 
6525       for (r = 0; r < 4; ++r) {
6526         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6527       }
6528       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6529     }
6530     break;
6531   case 3:
6532     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6533     cMax = PetscMin(cEnd, cMax);
6534     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6535     fMax = PetscMin(fEnd, fMax);
6536     /* Interior cells have 3 faces */
6537     for (c = cStart; c < cMax; ++c) {
6538       const PetscInt newp = cStartNew + (c - cStart)*4;
6539       const PetscInt *cone, *ornt;
6540       PetscInt       coneNew[3], orntNew[3];
6541 
6542       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6543       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6544       /* A triangle */
6545       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6546       orntNew[0] = ornt[0];
6547       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6548       orntNew[1] = -2;
6549       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6550       orntNew[2] = ornt[2];
6551       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6552       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6553 #if 1
6554       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);
6555       for (p = 0; p < 3; ++p) {
6556         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6557       }
6558 #endif
6559       /* B triangle */
6560       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6561       orntNew[0] = ornt[0];
6562       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6563       orntNew[1] = ornt[1];
6564       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6565       orntNew[2] = -2;
6566       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6567       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6568 #if 1
6569       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);
6570       for (p = 0; p < 3; ++p) {
6571         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6572       }
6573 #endif
6574       /* C triangle */
6575       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6576       orntNew[0] = -2;
6577       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6578       orntNew[1] = ornt[1];
6579       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6580       orntNew[2] = ornt[2];
6581       ierr       = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6582       ierr       = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6583 #if 1
6584       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);
6585       for (p = 0; p < 3; ++p) {
6586         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6587       }
6588 #endif
6589       /* D triangle */
6590       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6591       orntNew[0] = 0;
6592       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6593       orntNew[1] = 0;
6594       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6595       orntNew[2] = 0;
6596       ierr       = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6597       ierr       = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6598 #if 1
6599       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);
6600       for (p = 0; p < 3; ++p) {
6601         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);
6602       }
6603 #endif
6604     }
6605     /*
6606      2----3----3
6607      |         |
6608      |    B    |
6609      |         |
6610      0----4--- 1
6611      |         |
6612      |    A    |
6613      |         |
6614      0----2----1
6615      */
6616     /* Hybrid cells have 4 faces */
6617     for (c = cMax; c < cEnd; ++c) {
6618       const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6619       const PetscInt *cone, *ornt;
6620       PetscInt       coneNew[4], orntNew[4];
6621 
6622       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6623       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6624       /* A quad */
6625       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6626       orntNew[0] = ornt[0];
6627       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6628       orntNew[1] = ornt[1];
6629       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6630       orntNew[2] = 0;
6631       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6632       orntNew[3] = 0;
6633       ierr       = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6634       ierr       = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6635 #if 1
6636       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);
6637       for (p = 0; p < 4; ++p) {
6638         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);
6639       }
6640 #endif
6641       /* B quad */
6642       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6643       orntNew[0] = ornt[0];
6644       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6645       orntNew[1] = ornt[1];
6646       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6647       orntNew[2] = 0;
6648       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6649       orntNew[3] = 0;
6650       ierr       = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6651       ierr       = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6652 #if 1
6653       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);
6654       for (p = 0; p < 4; ++p) {
6655         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);
6656       }
6657 #endif
6658     }
6659     /* Interior split faces have 2 vertices and the same cells as the parent */
6660     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6661     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6662     for (f = fStart; f < fMax; ++f) {
6663       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6664 
6665       for (r = 0; r < 2; ++r) {
6666         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6667         const PetscInt *cone, *support;
6668         PetscInt       coneNew[2], coneSize, c, supportSize, s;
6669 
6670         ierr             = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6671         coneNew[0]       = vStartNew + (cone[0] - vStart);
6672         coneNew[1]       = vStartNew + (cone[1] - vStart);
6673         coneNew[(r+1)%2] = newv;
6674         ierr             = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6675 #if 1
6676         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6677         for (p = 0; p < 2; ++p) {
6678           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);
6679         }
6680 #endif
6681         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6682         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6683         for (s = 0; s < supportSize; ++s) {
6684           if (support[s] >= cMax) {
6685             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6686           } else {
6687             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6688             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6689             for (c = 0; c < coneSize; ++c) {
6690               if (cone[c] == f) break;
6691             }
6692             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6693           }
6694         }
6695         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6696 #if 1
6697         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6698         for (p = 0; p < supportSize; ++p) {
6699           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);
6700         }
6701 #endif
6702       }
6703     }
6704     /* Interior cell faces have 2 vertices and 2 cells */
6705     for (c = cStart; c < cMax; ++c) {
6706       const PetscInt *cone;
6707 
6708       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6709       for (r = 0; r < 3; ++r) {
6710         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6711         PetscInt       coneNew[2];
6712         PetscInt       supportNew[2];
6713 
6714         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6715         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6716         ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6717 #if 1
6718         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6719         for (p = 0; p < 2; ++p) {
6720           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);
6721         }
6722 #endif
6723         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6724         supportNew[1] = (c - cStart)*4 + 3;
6725         ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6726 #if 1
6727         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6728         for (p = 0; p < 2; ++p) {
6729           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);
6730         }
6731 #endif
6732       }
6733     }
6734     /* Interior hybrid faces have 2 vertices and the same cells */
6735     for (f = fMax; f < fEnd; ++f) {
6736       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6737       const PetscInt *cone;
6738       const PetscInt *support;
6739       PetscInt       coneNew[2];
6740       PetscInt       supportNew[2];
6741       PetscInt       size, s, r;
6742 
6743       ierr       = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6744       coneNew[0] = vStartNew + (cone[0] - vStart);
6745       coneNew[1] = vStartNew + (cone[1] - vStart);
6746       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6747 #if 1
6748       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6749       for (p = 0; p < 2; ++p) {
6750         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);
6751       }
6752 #endif
6753       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6754       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6755       for (s = 0; s < size; ++s) {
6756         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6757         for (r = 0; r < 2; ++r) {
6758           if (cone[r+2] == f) break;
6759         }
6760         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6761       }
6762       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6763 #if 1
6764       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6765       for (p = 0; p < size; ++p) {
6766         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);
6767       }
6768 #endif
6769     }
6770     /* Cell hybrid faces have 2 vertices and 2 cells */
6771     for (c = cMax; c < cEnd; ++c) {
6772       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6773       const PetscInt *cone;
6774       PetscInt       coneNew[2];
6775       PetscInt       supportNew[2];
6776 
6777       ierr       = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6778       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6779       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6780       ierr       = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6781 #if 1
6782       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6783       for (p = 0; p < 2; ++p) {
6784         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);
6785       }
6786 #endif
6787       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6788       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6789       ierr          = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6790 #if 1
6791       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6792       for (p = 0; p < 2; ++p) {
6793         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);
6794       }
6795 #endif
6796     }
6797     /* Old vertices have identical supports */
6798     for (v = vStart; v < vEnd; ++v) {
6799       const PetscInt newp = vStartNew + (v - vStart);
6800       const PetscInt *support, *cone;
6801       PetscInt       size, s;
6802 
6803       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6804       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6805       for (s = 0; s < size; ++s) {
6806         if (support[s] >= fMax) {
6807           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6808         } else {
6809           PetscInt r = 0;
6810 
6811           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6812           if (cone[1] == v) r = 1;
6813           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6814         }
6815       }
6816       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6817 #if 1
6818       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6819       for (p = 0; p < size; ++p) {
6820         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);
6821       }
6822 #endif
6823     }
6824     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6825     for (f = fStart; f < fMax; ++f) {
6826       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
6827       const PetscInt *cone, *support;
6828       PetscInt       size, newSize = 2, s;
6829 
6830       ierr          = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6831       ierr          = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6832       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6833       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6834       for (s = 0; s < size; ++s) {
6835         PetscInt r = 0;
6836 
6837         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6838         if (support[s] >= cMax) {
6839           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6840 
6841           newSize += 1;
6842         } else {
6843           if      (cone[1] == f) r = 1;
6844           else if (cone[2] == f) r = 2;
6845           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6846           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6847 
6848           newSize += 2;
6849         }
6850       }
6851       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6852 #if 1
6853       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6854       for (p = 0; p < newSize; ++p) {
6855         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);
6856       }
6857 #endif
6858     }
6859     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6860     break;
6861   default:
6862     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6863   }
6864   PetscFunctionReturn(0);
6865 }
6866 
6867 #undef __FUNCT__
6868 #define __FUNCT__ "CellRefinerSetCoordinates"
6869 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6870 {
6871   PetscSection   coordSection, coordSectionNew;
6872   Vec            coordinates, coordinatesNew;
6873   PetscScalar    *coords, *coordsNew;
6874   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6875   PetscErrorCode ierr;
6876 
6877   PetscFunctionBegin;
6878   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6879   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6880   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6881   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6882   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6883   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6884   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6885   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6886   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6887   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6888   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6889   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6890   if (fMax < 0) fMax = fEnd;
6891   switch (refiner) {
6892   case 1:
6893   case 2:
6894   case 3:
6895     /* Simplicial and Hex 2D */
6896     /* All vertices have the dim coordinates */
6897     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6898       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6899       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6900     }
6901     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6902     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6903     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6904     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6905     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6906     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6907     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6908     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6909     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6910     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6911     /* Old vertices have the same coordinates */
6912     for (v = vStart; v < vEnd; ++v) {
6913       const PetscInt newv = vStartNew + (v - vStart);
6914       PetscInt       off, offnew, d;
6915 
6916       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6917       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6918       for (d = 0; d < dim; ++d) {
6919         coordsNew[offnew+d] = coords[off+d];
6920       }
6921     }
6922     /* Face vertices have the average of endpoint coordinates */
6923     for (f = fStart; f < fMax; ++f) {
6924       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6925       const PetscInt *cone;
6926       PetscInt       coneSize, offA, offB, offnew, d;
6927 
6928       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6929       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6930       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6931       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6932       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6933       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6934       for (d = 0; d < dim; ++d) {
6935         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6936       }
6937     }
6938     /* Just Hex 2D */
6939     if (refiner == 2) {
6940       /* Cell vertices have the average of corner coordinates */
6941       for (c = cStart; c < cEnd; ++c) {
6942         const PetscInt newv  = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6943         PetscInt       *cone = PETSC_NULL;
6944         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6945 
6946         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6947         for (p = 0; p < closureSize*2; p += 2) {
6948           const PetscInt point = cone[p];
6949           if ((point >= vStart) && (point < vEnd)) cone[coneSize++] = point;
6950         }
6951         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6952         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6953         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6954         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6955         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6956         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6957         for (d = 0; d < dim; ++d) {
6958           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6959         }
6960         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6961       }
6962     }
6963     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6964     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6965     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6966     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6967     break;
6968   default:
6969     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6970   }
6971   PetscFunctionReturn(0);
6972 }
6973 
6974 #undef __FUNCT__
6975 #define __FUNCT__ "DMPlexCreateProcessSF"
6976 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6977 {
6978   PetscInt          numRoots, numLeaves, l;
6979   const PetscInt    *localPoints;
6980   const PetscSFNode *remotePoints;
6981   PetscInt          *localPointsNew;
6982   PetscSFNode       *remotePointsNew;
6983   PetscInt          *ranks, *ranksNew;
6984   PetscErrorCode    ierr;
6985 
6986   PetscFunctionBegin;
6987   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6988   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6989   for (l = 0; l < numLeaves; ++l) {
6990     ranks[l] = remotePoints[l].rank;
6991   }
6992   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6993   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6994   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6995   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6996   for (l = 0; l < numLeaves; ++l) {
6997     ranksNew[l]              = ranks[l];
6998     localPointsNew[l]        = l;
6999     remotePointsNew[l].index = 0;
7000     remotePointsNew[l].rank  = ranksNew[l];
7001   }
7002   ierr = PetscFree(ranks);CHKERRQ(ierr);
7003   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
7004   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
7005   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
7006   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7007   PetscFunctionReturn(0);
7008 }
7009 
7010 #undef __FUNCT__
7011 #define __FUNCT__ "CellRefinerCreateSF"
7012 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7013 {
7014   PetscSF           sf, sfNew, sfProcess;
7015   IS                processRanks;
7016   MPI_Datatype      depthType;
7017   PetscInt          numRoots, numLeaves, numLeavesNew = 0, l, m;
7018   const PetscInt    *localPoints, *neighbors;
7019   const PetscSFNode *remotePoints;
7020   PetscInt          *localPointsNew;
7021   PetscSFNode       *remotePointsNew;
7022   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7023   PetscInt          depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7024   PetscErrorCode    ierr;
7025 
7026   PetscFunctionBegin;
7027   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7028   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7029   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7030   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7031   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7032   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7033   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7034   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7035   switch (refiner) {
7036   case 3:
7037     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7038     cMax = PetscMin(cEnd, cMax);
7039     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7040     fMax = PetscMin(fEnd, fMax);
7041   }
7042   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7043   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7044   /* Caculate size of new SF */
7045   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7046   if (numRoots < 0) PetscFunctionReturn(0);
7047   for (l = 0; l < numLeaves; ++l) {
7048     const PetscInt p = localPoints[l];
7049 
7050     switch (refiner) {
7051     case 1:
7052       /* Simplicial 2D */
7053       if ((p >= vStart) && (p < vEnd)) {
7054         /* Old vertices stay the same */
7055         ++numLeavesNew;
7056       } else if ((p >= fStart) && (p < fEnd)) {
7057         /* Old faces add new faces and vertex */
7058         numLeavesNew += 1 + 2;
7059       } else if ((p >= cStart) && (p < cEnd)) {
7060         /* Old cells add new cells and interior faces */
7061         numLeavesNew += 4 + 3;
7062       }
7063       break;
7064     case 2:
7065       /* Hex 2D */
7066       if ((p >= vStart) && (p < vEnd)) {
7067         /* Old vertices stay the same */
7068         ++numLeavesNew;
7069       } else if ((p >= fStart) && (p < fEnd)) {
7070         /* Old faces add new faces and vertex */
7071         numLeavesNew += 1 + 2;
7072       } else if ((p >= cStart) && (p < cEnd)) {
7073         /* Old cells add new cells and interior faces */
7074         numLeavesNew += 4 + 4;
7075       }
7076       break;
7077     default:
7078       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7079     }
7080   }
7081   /* Communicate depthSizes for each remote rank */
7082   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7083   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7084   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7085   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);
7086   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7087   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7088   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7089   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7090   for (n = 0; n < numNeighbors; ++n) {
7091     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7092   }
7093   depthSizeOld[depth]   = cMax;
7094   depthSizeOld[0]       = vMax;
7095   depthSizeOld[depth-1] = fMax;
7096   depthSizeOld[1]       = eMax;
7097 
7098   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7099   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7100 
7101   depthSizeOld[depth]   = cEnd - cStart;
7102   depthSizeOld[0]       = vEnd - vStart;
7103   depthSizeOld[depth-1] = fEnd - fStart;
7104   depthSizeOld[1]       = eEnd - eStart;
7105 
7106   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7107   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7108   for (n = 0; n < numNeighbors; ++n) {
7109     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7110   }
7111   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7112   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7113   /* Calculate new point SF */
7114   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7115   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7116   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7117   for (l = 0, m = 0; l < numLeaves; ++l) {
7118     PetscInt    p     = localPoints[l];
7119     PetscInt    rp    = remotePoints[l].index, n;
7120     PetscMPIInt rrank = remotePoints[l].rank;
7121 
7122     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7123     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7124     switch (refiner) {
7125     case 1:
7126       /* Simplicial 2D */
7127       if ((p >= vStart) && (p < vEnd)) {
7128         /* Old vertices stay the same */
7129         localPointsNew[m]        = vStartNew     + (p  - vStart);
7130         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7131         remotePointsNew[m].rank  = rrank;
7132         ++m;
7133       } else if ((p >= fStart) && (p < fEnd)) {
7134         /* Old faces add new faces and vertex */
7135         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7136         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7137         remotePointsNew[m].rank  = rrank;
7138         ++m;
7139         for (r = 0; r < 2; ++r, ++m) {
7140           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7141           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7142           remotePointsNew[m].rank  = rrank;
7143         }
7144       } else if ((p >= cStart) && (p < cEnd)) {
7145         /* Old cells add new cells and interior faces */
7146         for (r = 0; r < 4; ++r, ++m) {
7147           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7148           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7149           remotePointsNew[m].rank  = rrank;
7150         }
7151         for (r = 0; r < 3; ++r, ++m) {
7152           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7153           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7154           remotePointsNew[m].rank  = rrank;
7155         }
7156       }
7157       break;
7158     case 2:
7159       /* Hex 2D */
7160       if ((p >= vStart) && (p < vEnd)) {
7161         /* Old vertices stay the same */
7162         localPointsNew[m]        = vStartNew     + (p  - vStart);
7163         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7164         remotePointsNew[m].rank  = rrank;
7165         ++m;
7166       } else if ((p >= fStart) && (p < fEnd)) {
7167         /* Old faces add new faces and vertex */
7168         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7169         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7170         remotePointsNew[m].rank  = rrank;
7171         ++m;
7172         for (r = 0; r < 2; ++r, ++m) {
7173           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7174           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7175           remotePointsNew[m].rank  = rrank;
7176         }
7177       } else if ((p >= cStart) && (p < cEnd)) {
7178         /* Old cells add new cells and interior faces */
7179         for (r = 0; r < 4; ++r, ++m) {
7180           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7181           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7182           remotePointsNew[m].rank  = rrank;
7183         }
7184         for (r = 0; r < 4; ++r, ++m) {
7185           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7186           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7187           remotePointsNew[m].rank  = rrank;
7188         }
7189       }
7190       break;
7191     case 3:
7192       /* Hybrid simplicial 2D */
7193       if ((p >= vStart) && (p < vEnd)) {
7194         /* Old vertices stay the same */
7195         localPointsNew[m]        = vStartNew     + (p  - vStart);
7196         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7197         remotePointsNew[m].rank  = rrank;
7198         ++m;
7199       } else if ((p >= fStart) && (p < fMax)) {
7200         /* Old interior faces add new faces and vertex */
7201         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7202         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7203         remotePointsNew[m].rank  = rrank;
7204         ++m;
7205         for (r = 0; r < 2; ++r, ++m) {
7206           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7207           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7208           remotePointsNew[m].rank  = rrank;
7209         }
7210       } else if ((p >= fMax) && (p < fEnd)) {
7211         /* Old hybrid faces stay the same */
7212         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7213         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7214         remotePointsNew[m].rank  = rrank;
7215         ++m;
7216       } else if ((p >= cStart) && (p < cMax)) {
7217         /* Old interior cells add new cells and interior faces */
7218         for (r = 0; r < 4; ++r, ++m) {
7219           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7220           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7221           remotePointsNew[m].rank  = rrank;
7222         }
7223         for (r = 0; r < 3; ++r, ++m) {
7224           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7225           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7226           remotePointsNew[m].rank  = rrank;
7227         }
7228       } else if ((p >= cStart) && (p < cMax)) {
7229         /* Old hybrid cells add new cells and hybrid face */
7230         for (r = 0; r < 2; ++r, ++m) {
7231           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7232           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7233           remotePointsNew[m].rank  = rrank;
7234         }
7235         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7236         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]);
7237         remotePointsNew[m].rank  = rrank;
7238         ++m;
7239       }
7240       break;
7241     default:
7242       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7243     }
7244   }
7245   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7246   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7247   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7248   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7249   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7250   PetscFunctionReturn(0);
7251 }
7252 
7253 #undef __FUNCT__
7254 #define __FUNCT__ "CellRefinerCreateLabels"
7255 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7256 {
7257   PetscInt       numLabels, l;
7258   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7259   PetscErrorCode ierr;
7260 
7261   PetscFunctionBegin;
7262   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7263   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7264   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7265   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7266 
7267   cStartNew = 0;
7268   vStartNew = depthSize[2];
7269   fStartNew = depthSize[2] + depthSize[0];
7270 
7271   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7272   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7273   switch (refiner) {
7274   case 3:
7275     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7276     cMax = PetscMin(cEnd, cMax);
7277     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7278     fMax = PetscMin(fEnd, fMax);
7279   }
7280   for (l = 0; l < numLabels; ++l) {
7281     DMLabel        label, labelNew;
7282     const char     *lname;
7283     PetscBool      isDepth;
7284     IS             valueIS;
7285     const PetscInt *values;
7286     PetscInt       numValues, val;
7287 
7288     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7289     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7290     if (isDepth) continue;
7291     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7292     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7293     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7294     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7295     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7296     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7297     for (val = 0; val < numValues; ++val) {
7298       IS             pointIS;
7299       const PetscInt *points;
7300       PetscInt       numPoints, n;
7301 
7302       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7303       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7304       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7305       for (n = 0; n < numPoints; ++n) {
7306         const PetscInt p = points[n];
7307         switch (refiner) {
7308         case 1:
7309           /* Simplicial 2D */
7310           if ((p >= vStart) && (p < vEnd)) {
7311             /* Old vertices stay the same */
7312             newp = vStartNew + (p - vStart);
7313             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7314           } else if ((p >= fStart) && (p < fEnd)) {
7315             /* Old faces add new faces and vertex */
7316             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7317             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7318             for (r = 0; r < 2; ++r) {
7319               newp = fStartNew + (p - fStart)*2 + r;
7320               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7321             }
7322           } else if ((p >= cStart) && (p < cEnd)) {
7323             /* Old cells add new cells and interior faces */
7324             for (r = 0; r < 4; ++r) {
7325               newp = cStartNew + (p - cStart)*4 + r;
7326               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7327             }
7328             for (r = 0; r < 3; ++r) {
7329               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7330               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7331             }
7332           }
7333           break;
7334         case 2:
7335           /* Hex 2D */
7336           if ((p >= vStart) && (p < vEnd)) {
7337             /* Old vertices stay the same */
7338             newp = vStartNew + (p - vStart);
7339             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7340           } else if ((p >= fStart) && (p < fEnd)) {
7341             /* Old faces add new faces and vertex */
7342             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7343             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7344             for (r = 0; r < 2; ++r) {
7345               newp = fStartNew + (p - fStart)*2 + r;
7346               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7347             }
7348           } else if ((p >= cStart) && (p < cEnd)) {
7349             /* Old cells add new cells and interior faces and vertex */
7350             for (r = 0; r < 4; ++r) {
7351               newp = cStartNew + (p - cStart)*4 + r;
7352               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7353             }
7354             for (r = 0; r < 4; ++r) {
7355               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7356               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7357             }
7358             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7359             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7360           }
7361           break;
7362         case 3:
7363           /* Hybrid simplicial 2D */
7364           if ((p >= vStart) && (p < vEnd)) {
7365             /* Old vertices stay the same */
7366             newp = vStartNew + (p - vStart);
7367             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7368           } else if ((p >= fStart) && (p < fMax)) {
7369             /* Old interior faces add new faces and vertex */
7370             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7371             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7372             for (r = 0; r < 2; ++r) {
7373               newp = fStartNew + (p - fStart)*2 + r;
7374               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7375             }
7376           } else if ((p >= fMax) && (p < fEnd)) {
7377             /* Old hybrid faces stay the same */
7378             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7379             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7380           } else if ((p >= cStart) && (p < cMax)) {
7381             /* Old interior cells add new cells and interior faces */
7382             for (r = 0; r < 4; ++r) {
7383               newp = cStartNew + (p - cStart)*4 + r;
7384               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7385             }
7386             for (r = 0; r < 3; ++r) {
7387               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7388               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7389             }
7390           } else if ((p >= cMax) && (p < cEnd)) {
7391             /* Old hybrid cells add new cells and hybrid face */
7392             for (r = 0; r < 2; ++r) {
7393               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7394               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7395             }
7396             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7397             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7398           }
7399           break;
7400         default:
7401           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7402         }
7403       }
7404       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7405       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7406     }
7407     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7408     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7409     if (0) {
7410       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7411       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7412       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7413     }
7414   }
7415   PetscFunctionReturn(0);
7416 }
7417 
7418 #undef __FUNCT__
7419 #define __FUNCT__ "DMPlexRefine_Uniform"
7420 /* This will only work for interpolated meshes */
7421 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7422 {
7423   DM             rdm;
7424   PetscInt       *depthSize;
7425   PetscInt       dim, depth = 0, d, pStart = 0, pEnd = 0;
7426   PetscErrorCode ierr;
7427 
7428   PetscFunctionBegin;
7429   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7430   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7431   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7432   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7433   /* Calculate number of new points of each depth */
7434   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7435   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7436   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7437   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7438   /* Step 1: Set chart */
7439   for (d = 0; d <= depth; ++d) pEnd += depthSize[d];
7440   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7441   /* Step 2: Set cone/support sizes */
7442   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7443   /* Step 3: Setup refined DM */
7444   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7445   /* Step 4: Set cones and supports */
7446   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7447   /* Step 5: Stratify */
7448   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7449   /* Step 6: Set coordinates for vertices */
7450   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7451   /* Step 7: Create pointSF */
7452   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7453   /* Step 8: Create labels */
7454   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7455   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7456 
7457   *dmRefined = rdm;
7458 #if 0
7459   DM_Plex  *mesh = (DM_Plex*) dm->data;
7460   PetscInt dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7461   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7462 
7463   PetscFunctionBegin;
7464   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7465   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7466   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7467   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7468   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7469 
7470   /* Count number of new cells which are normal and extra */
7471   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7472 
7473   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7474   for (c = cStart; c < cEnd2; ++c) {
7475     PetscInt n;
7476     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7477 
7478     newNumCellsNormal += n;
7479   }
7480   for (c = cEnd2; c < cEnd; ++c) {
7481     PetscInt n;
7482     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7483 
7484     newNumCellsExtra += n;
7485   }
7486   newNumCells = newNumCellsNormal + newNumCellsExtra;
7487   /* Count number of new vertices which are normal and extra */
7488   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7489   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7490   for (c = cStart; c < cEnd; ++c) {
7491     PetscInt *closure = PETSC_NULL;
7492     PetscInt closureSize, numCorners = 0, p;
7493 
7494     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7495     for (p = 0; p < closureSize*2; p += 2) {
7496       const PetscInt point = closure[p];
7497       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
7498     }
7499     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7500     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7501   }
7502   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7503   for (c = cEnd2; c < cEnd; ++c) {
7504     PetscInt *closure = PETSC_NULL;
7505     PetscInt closureSize, numCorners = 0, p;
7506 
7507     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7508     for (p = 0; p < closureSize*2; p += 2) {
7509       const PetscInt point = closure[p];
7510       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
7511     }
7512     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7513     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7514   } /* for */
7515   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7516   newNumVertices      = newNumVerticesNormal + newNumVerticesExtra;
7517 
7518 #if 1
7519   PetscInt oldNumCellsNormal = cEnd2 - cStart;
7520   PetscInt oldNumCellsExtra  = cEnd  - cEnd2;
7521   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7522   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7523   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7524   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7525   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7526   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7527   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7528   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7529   ierr = PetscSynchronizedFlush(comm);
7530 #endif
7531 
7532   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7533   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7534   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7535   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7536   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7537   /* Set cone and support sizes for new normal cells */
7538   PetscInt newCell = 0;
7539   for (c = cStart; c < cEnd2; ++c) {
7540     PetscInt coneSize, n, i;
7541 
7542     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7543     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7544     for (i = 0; i < n; ++i, ++newCell) {
7545       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7546     }
7547 
7548     PetscInt *closure = PETSC_NULL;
7549     PetscInt closureSize, numCorners = 0, p;
7550 
7551     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7552     for (p = 0; p < closureSize*2; p += 2) {
7553       const PetscInt point = closure[p];
7554       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
7555     }
7556     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7557     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7558   }
7559 
7560   /* Reset current new cell value and loop over censored cells. */
7561   curNewCell  = _orderNewMesh->cellsCensored().min();
7562   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7563   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7564     /* Set new cone and support sizes */
7565     cV.clear();
7566     sieve->cone(*c_iter, cV);
7567     const point_type * cone   = cV.getPoints();
7568     const int        coneSize = cV.getSize();
7569 
7570     const point_type * newCells;
7571     int              numNewCells = 0;
7572     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7573 
7574     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7575       newSieve->setConeSize(curNewCell, coneSize);
7576       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7577         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7578       } /* for */
7579     } /* for */
7580   } /* for */
7581   newSieve->allocate();
7582 
7583   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7584 
7585   /* Create refined cells in new sieve. */
7586   curNewCell  = _orderNewMesh->cellsNormal().min();
7587   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7588   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7589     cV.clear();
7590     sieve->cone(*c_iter, cV);
7591     const point_type *cone    = cV.getPoints();
7592     const int        coneSize = cV.getSize();
7593 
7594     const point_type * newCells;
7595     int              numNewCells = 0;
7596     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7597 
7598     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7599       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7600     } /* for */
7601   } /* for */
7602   curNewCell = _orderNewMesh->cellsCensored().min();
7603   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7604   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7605     cV.clear();
7606     sieve->cone(*c_iter, cV);
7607     const point_type *cone    = cV.getPoints();
7608     const int        coneSize = cV.getSize();
7609 
7610     const point_type *newCells;
7611     int              numNewCells = 0;
7612     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7613 
7614     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7615       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7616     } /* for */
7617   } /* for */
7618   newSieve->symmetrize();
7619 
7620   /* Set coordinates in refined mesh. */
7621   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7622   assert(!coordinates.isNull());
7623   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7624   assert(!newCoordinates.isNull());
7625 
7626   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7627   assert(vertices->size() > 0);
7628   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7629   assert(spaceDim > 0);
7630   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7631 
7632   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7633   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7634     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7635   } /* for */
7636   newCoordinates->allocatePoint();
7637 
7638   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7639   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7640     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7641     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7642   } /* for */
7643   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7644   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7645     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7646     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7647   } /* for */
7648 
7649   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7650 
7651   /* Create sensored depth */
7652   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7653   assert(!censoredLabel.isNull());
7654 
7655   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7656 
7657   newSieve->roots(depthVisitor);
7658   while (depthVisitor.isModified()) {
7659     /* FIX: Avoid the copy here somehow by fixing the traversal */
7660     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7661 
7662     depthVisitor.clear();
7663     newSieve->support(modifiedPoints, depthVisitor);
7664   } /* while */
7665 
7666   /* Stratify refined mesh */
7667   /* Calculate new point SF */
7668   _calcNewOverlap(newMesh, mesh, refiner);
7669   /* Calculate new labels */
7670   _createLabels(newMesh, mesh, refiner);
7671 #endif
7672   PetscFunctionReturn(0);
7673 }
7674 
7675 #undef __FUNCT__
7676 #define __FUNCT__ "DMPlexSetRefinementUniform"
7677 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7678 {
7679   DM_Plex *mesh = (DM_Plex*) dm->data;
7680 
7681   PetscFunctionBegin;
7682   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7683   mesh->refinementUniform = refinementUniform;
7684   PetscFunctionReturn(0);
7685 }
7686 
7687 #undef __FUNCT__
7688 #define __FUNCT__ "DMPlexGetRefinementUniform"
7689 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7690 {
7691   DM_Plex *mesh = (DM_Plex*) dm->data;
7692 
7693   PetscFunctionBegin;
7694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7695   PetscValidPointer(refinementUniform,  2);
7696   *refinementUniform = mesh->refinementUniform;
7697   PetscFunctionReturn(0);
7698 }
7699 
7700 #undef __FUNCT__
7701 #define __FUNCT__ "DMPlexSetRefinementLimit"
7702 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7703 {
7704   DM_Plex *mesh = (DM_Plex*) dm->data;
7705 
7706   PetscFunctionBegin;
7707   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7708   mesh->refinementLimit = refinementLimit;
7709   PetscFunctionReturn(0);
7710 }
7711 
7712 #undef __FUNCT__
7713 #define __FUNCT__ "DMPlexGetRefinementLimit"
7714 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7715 {
7716   DM_Plex *mesh = (DM_Plex*) dm->data;
7717 
7718   PetscFunctionBegin;
7719   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7720   PetscValidPointer(refinementLimit,  2);
7721   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7722   *refinementLimit = mesh->refinementLimit;
7723   PetscFunctionReturn(0);
7724 }
7725 
7726 #undef __FUNCT__
7727 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7728 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7729 {
7730   PetscInt       dim, cStart, coneSize, cMax;
7731   PetscErrorCode ierr;
7732 
7733   PetscFunctionBegin;
7734   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7735   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7736   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7737   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7738   switch (dim) {
7739   case 2:
7740     switch (coneSize) {
7741     case 3:
7742       if (cMax >= 0) *cellRefiner = 3; /* Hybrid */
7743       else *cellRefiner = 1; /* Triangular */
7744       break;
7745     case 4:
7746       if (cMax >= 0) *cellRefiner = 4; /* Hybrid */
7747       else *cellRefiner = 2; /* Quadrilateral */
7748       break;
7749     default:
7750       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7751     }
7752     break;
7753   default:
7754     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7755   }
7756   PetscFunctionReturn(0);
7757 }
7758 
7759 #undef __FUNCT__
7760 #define __FUNCT__ "DMRefine_Plex"
7761 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7762 {
7763   PetscReal      refinementLimit;
7764   PetscInt       dim, cStart, cEnd;
7765   char           genname[1024], *name = PETSC_NULL;
7766   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7767   PetscErrorCode ierr;
7768 
7769   PetscFunctionBegin;
7770   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7771   if (isUniform) {
7772     CellRefiner cellRefiner;
7773 
7774     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7775     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7776     PetscFunctionReturn(0);
7777   }
7778   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7779   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7780   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7781   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7782   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7783   if (flg) name = genname;
7784   if (name) {
7785     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7786     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7787     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7788   }
7789   switch (dim) {
7790   case 2:
7791     if (!name || isTriangle) {
7792 #if defined(PETSC_HAVE_TRIANGLE)
7793       double   *maxVolumes;
7794       PetscInt c;
7795 
7796       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7797       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7798       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7799 #else
7800       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7801 #endif
7802     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7803     break;
7804   case 3:
7805     if (!name || isCTetgen) {
7806 #if defined(PETSC_HAVE_CTETGEN)
7807       PetscReal *maxVolumes;
7808       PetscInt  c;
7809 
7810       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7811       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7812       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7813 #else
7814       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7815 #endif
7816     } else if (isTetgen) {
7817 #if defined(PETSC_HAVE_TETGEN)
7818       double   *maxVolumes;
7819       PetscInt c;
7820 
7821       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7822       for (c = 0; c < cEnd-cStart; ++c) maxVolumes[c] = refinementLimit;
7823       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7824 #else
7825       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7826 #endif
7827     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7828     break;
7829   default:
7830     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7831   }
7832   PetscFunctionReturn(0);
7833 }
7834 
7835 #undef __FUNCT__
7836 #define __FUNCT__ "DMPlexGetDepth"
7837 /*@
7838   DMPlexGetDepth - get the number of strata
7839 
7840   Not Collective
7841 
7842   Input Parameters:
7843 . dm           - The DMPlex object
7844 
7845   Output Parameters:
7846 . depth - number of strata
7847 
7848   Level: developer
7849 
7850   Notes:
7851   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7852 
7853 .keywords: mesh, points
7854 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7855 @*/
7856 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7857 {
7858   PetscInt       d;
7859   PetscErrorCode ierr;
7860 
7861   PetscFunctionBegin;
7862   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7863   PetscValidPointer(depth, 2);
7864   ierr   = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7865   *depth = d-1;
7866   PetscFunctionReturn(0);
7867 }
7868 
7869 #undef __FUNCT__
7870 #define __FUNCT__ "DMPlexGetDepthStratum"
7871 /*@
7872   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7873 
7874   Not Collective
7875 
7876   Input Parameters:
7877 + dm           - The DMPlex object
7878 - stratumValue - The requested depth
7879 
7880   Output Parameters:
7881 + start - The first point at this depth
7882 - end   - One beyond the last point at this depth
7883 
7884   Level: developer
7885 
7886 .keywords: mesh, points
7887 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7888 @*/
7889 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7890 {
7891   DM_Plex        *mesh = (DM_Plex*) dm->data;
7892   DMLabel        next  = mesh->labels;
7893   PetscBool      flg   = PETSC_FALSE;
7894   PetscInt       depth;
7895   PetscErrorCode ierr;
7896 
7897   PetscFunctionBegin;
7898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7899   if (stratumValue < 0) {
7900     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7901     PetscFunctionReturn(0);
7902   } else {
7903     PetscInt pStart, pEnd;
7904 
7905     if (start) *start = 0;
7906     if (end)   *end   = 0;
7907     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7908     if (pStart == pEnd) PetscFunctionReturn(0);
7909   }
7910   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7911   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7912   /* We should have a generic GetLabel() and a Label class */
7913   while (next) {
7914     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7915     if (flg) break;
7916     next = next->next;
7917   }
7918   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7919   depth = stratumValue;
7920   if ((depth < 0) || (depth >= next->numStrata)) {
7921     if (start) *start = 0;
7922     if (end)   *end   = 0;
7923   } else {
7924     if (start) *start = next->points[next->stratumOffsets[depth]];
7925     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7926   }
7927   PetscFunctionReturn(0);
7928 }
7929 
7930 #undef __FUNCT__
7931 #define __FUNCT__ "DMPlexGetHeightStratum"
7932 /*@
7933   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7934 
7935   Not Collective
7936 
7937   Input Parameters:
7938 + dm           - The DMPlex object
7939 - stratumValue - The requested height
7940 
7941   Output Parameters:
7942 + start - The first point at this height
7943 - end   - One beyond the last point at this height
7944 
7945   Level: developer
7946 
7947 .keywords: mesh, points
7948 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7949 @*/
7950 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7951 {
7952   DM_Plex        *mesh = (DM_Plex*) dm->data;
7953   DMLabel        next  = mesh->labels;
7954   PetscBool      flg   = PETSC_FALSE;
7955   PetscInt       depth;
7956   PetscErrorCode ierr;
7957 
7958   PetscFunctionBegin;
7959   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7960   if (stratumValue < 0) {
7961     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7962   } else {
7963     PetscInt pStart, pEnd;
7964 
7965     if (start) *start = 0;
7966     if (end)   *end   = 0;
7967     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7968     if (pStart == pEnd) PetscFunctionReturn(0);
7969   }
7970   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7971   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7972   /* We should have a generic GetLabel() and a Label class */
7973   while (next) {
7974     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7975     if (flg) break;
7976     next = next->next;
7977   }
7978   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7979   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7980   if ((depth < 0) || (depth >= next->numStrata)) {
7981     if (start) *start = 0;
7982     if (end)   *end   = 0;
7983   } else {
7984     if (start) *start = next->points[next->stratumOffsets[depth]];
7985     if (end)   *end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;
7986   }
7987   PetscFunctionReturn(0);
7988 }
7989 
7990 #undef __FUNCT__
7991 #define __FUNCT__ "DMPlexCreateSectionInitial"
7992 /* Set the number of dof on each point and separate by fields */
7993 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7994 {
7995   PetscInt       *numDofTot;
7996   PetscInt       pStart = 0, pEnd = 0;
7997   PetscInt       p, d, f;
7998   PetscErrorCode ierr;
7999 
8000   PetscFunctionBegin;
8001   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
8002   for (d = 0; d <= dim; ++d) {
8003     numDofTot[d] = 0;
8004     for (f = 0; f < numFields; ++f) numDofTot[d] += numDof[f*(dim+1)+d];
8005   }
8006   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
8007   if (numFields > 0) {
8008     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
8009     if (numComp) {
8010       for (f = 0; f < numFields; ++f) {
8011         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
8012       }
8013     }
8014   }
8015   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8016   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
8017   for (d = 0; d <= dim; ++d) {
8018     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
8019     for (p = pStart; p < pEnd; ++p) {
8020       for (f = 0; f < numFields; ++f) {
8021         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
8022       }
8023       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
8024     }
8025   }
8026   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
8027   PetscFunctionReturn(0);
8028 }
8029 
8030 #undef __FUNCT__
8031 #define __FUNCT__ "DMPlexCreateSectionBCDof"
8032 /* Set the number of dof on each point and separate by fields
8033    If constDof is PETSC_DETERMINE, constrain every dof on the point
8034 */
8035 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
8036 {
8037   PetscInt       numFields;
8038   PetscInt       bc;
8039   PetscErrorCode ierr;
8040 
8041   PetscFunctionBegin;
8042   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8043   for (bc = 0; bc < numBC; ++bc) {
8044     PetscInt       field = 0;
8045     const PetscInt *idx;
8046     PetscInt       n, i;
8047 
8048     if (numFields) field = bcField[bc];
8049     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
8050     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8051     for (i = 0; i < n; ++i) {
8052       const PetscInt p        = idx[i];
8053       PetscInt       numConst = constDof;
8054 
8055       /* Constrain every dof on the point */
8056       if (numConst < 0) {
8057         if (numFields) {
8058           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
8059         } else {
8060           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
8061         }
8062       }
8063       if (numFields) {
8064         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
8065       }
8066       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
8067     }
8068     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8069   }
8070   PetscFunctionReturn(0);
8071 }
8072 
8073 #undef __FUNCT__
8074 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
8075 /* Set the constrained indices on each point and separate by fields */
8076 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
8077 {
8078   PetscInt       *maxConstraints;
8079   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
8080   PetscErrorCode ierr;
8081 
8082   PetscFunctionBegin;
8083   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8084   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8085   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
8086   for (f = 0; f <= numFields; ++f) maxConstraints[f] = 0;
8087   for (p = pStart; p < pEnd; ++p) {
8088     PetscInt cdof;
8089 
8090     if (numFields) {
8091       for (f = 0; f < numFields; ++f) {
8092         ierr              = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
8093         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
8094       }
8095     } else {
8096       ierr              = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8097       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
8098     }
8099   }
8100   for (f = 0; f < numFields; ++f) {
8101     maxConstraints[numFields] += maxConstraints[f];
8102   }
8103   if (maxConstraints[numFields]) {
8104     PetscInt *indices;
8105 
8106     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8107     for (p = pStart; p < pEnd; ++p) {
8108       PetscInt cdof, d;
8109 
8110       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8111       if (cdof) {
8112         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
8113         if (numFields) {
8114           PetscInt numConst = 0, foff = 0;
8115 
8116           for (f = 0; f < numFields; ++f) {
8117             PetscInt cfdof, fdof;
8118 
8119             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8120             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
8121             /* Change constraint numbering from absolute local dof number to field relative local dof number */
8122             for (d = 0; d < cfdof; ++d) indices[numConst+d] = d;
8123             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
8124             for (d = 0; d < cfdof; ++d) indices[numConst+d] += foff;
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) indices[d] = d;
8131         }
8132         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8133       }
8134     }
8135     ierr = PetscFree(indices);CHKERRQ(ierr);
8136   }
8137   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
8138   PetscFunctionReturn(0);
8139 }
8140 
8141 #undef __FUNCT__
8142 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
8143 /* Set the constrained field indices on each point */
8144 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
8145 {
8146   const PetscInt *points, *indices;
8147   PetscInt       numFields, maxDof, numPoints, p, numConstraints;
8148   PetscErrorCode ierr;
8149 
8150   PetscFunctionBegin;
8151   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8152   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8153 
8154   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8155   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8156   if (!constraintIndices) {
8157     PetscInt *idx, i;
8158 
8159     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8160     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8161     for (i = 0; i < maxDof; ++i) idx[i] = i;
8162     for (p = 0; p < numPoints; ++p) {
8163       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8164     }
8165     ierr = PetscFree(idx);CHKERRQ(ierr);
8166   } else {
8167     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8168     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8169     for (p = 0; p < numPoints; ++p) {
8170       PetscInt fcdof;
8171 
8172       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8173       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);
8174       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8175     }
8176     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8177   }
8178   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8179   PetscFunctionReturn(0);
8180 }
8181 
8182 #undef __FUNCT__
8183 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8184 /* Set the constrained indices on each point and separate by fields */
8185 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8186 {
8187   PetscInt       *indices;
8188   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8189   PetscErrorCode ierr;
8190 
8191   PetscFunctionBegin;
8192   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8193   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8194   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8195   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8196   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8197   for (p = pStart; p < pEnd; ++p) {
8198     PetscInt cdof, d;
8199 
8200     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8201     if (cdof) {
8202       PetscInt numConst = 0, foff = 0;
8203 
8204       for (f = 0; f < numFields; ++f) {
8205         const PetscInt *fcind;
8206         PetscInt       fdof, fcdof;
8207 
8208         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8209         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8210         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8211         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8212         for (d = 0; d < fcdof; ++d) indices[numConst+d] = fcind[d]+foff;
8213         foff     += fdof;
8214         numConst += fcdof;
8215       }
8216       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8217       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8218     }
8219   }
8220   ierr = PetscFree(indices);CHKERRQ(ierr);
8221   PetscFunctionReturn(0);
8222 }
8223 
8224 #undef __FUNCT__
8225 #define __FUNCT__ "DMPlexCreateSection"
8226 /*@C
8227   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8228 
8229   Not Collective
8230 
8231   Input Parameters:
8232 + dm        - The DMPlex object
8233 . dim       - The spatial dimension of the problem
8234 . numFields - The number of fields in the problem
8235 . numComp   - An array of size numFields that holds the number of components for each field
8236 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8237 . numBC     - The number of boundary conditions
8238 . bcField   - An array of size numBC giving the field number for each boundry condition
8239 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8240 
8241   Output Parameter:
8242 . section - The PetscSection object
8243 
8244   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
8245   nubmer of dof for field 0 on each edge.
8246 
8247   Level: developer
8248 
8249 .keywords: mesh, elements
8250 .seealso: DMPlexCreate(), PetscSectionCreate()
8251 @*/
8252 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8253 {
8254   PetscErrorCode ierr;
8255 
8256   PetscFunctionBegin;
8257   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8258   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8259   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8260   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8261   {
8262     PetscBool view = PETSC_FALSE;
8263 
8264     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8265     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8266   }
8267   PetscFunctionReturn(0);
8268 }
8269 
8270 #undef __FUNCT__
8271 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8272 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8273 {
8274   PetscSection   section;
8275   PetscErrorCode ierr;
8276 
8277   PetscFunctionBegin;
8278   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8279   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8280   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8281   PetscFunctionReturn(0);
8282 }
8283 
8284 #undef __FUNCT__
8285 #define __FUNCT__ "DMPlexGetCoordinateSection"
8286 /*@
8287   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8288 
8289   Not Collective
8290 
8291   Input Parameter:
8292 . dm - The DMPlex object
8293 
8294   Output Parameter:
8295 . section - The PetscSection object
8296 
8297   Level: intermediate
8298 
8299 .keywords: mesh, coordinates
8300 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8301 @*/
8302 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8303 {
8304   DM             cdm;
8305   PetscErrorCode ierr;
8306 
8307   PetscFunctionBegin;
8308   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8309   PetscValidPointer(section, 2);
8310   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8311   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8312   PetscFunctionReturn(0);
8313 }
8314 
8315 #undef __FUNCT__
8316 #define __FUNCT__ "DMPlexSetCoordinateSection"
8317 /*@
8318   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8319 
8320   Not Collective
8321 
8322   Input Parameters:
8323 + dm      - The DMPlex object
8324 - section - The PetscSection object
8325 
8326   Level: intermediate
8327 
8328 .keywords: mesh, coordinates
8329 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8330 @*/
8331 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8332 {
8333   DM             cdm;
8334   PetscErrorCode ierr;
8335 
8336   PetscFunctionBegin;
8337   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8338   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8339   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8340   PetscFunctionReturn(0);
8341 }
8342 
8343 #undef __FUNCT__
8344 #define __FUNCT__ "DMPlexGetConeSection"
8345 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8346 {
8347   DM_Plex *mesh = (DM_Plex*) dm->data;
8348 
8349   PetscFunctionBegin;
8350   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8351   if (section) *section = mesh->coneSection;
8352   PetscFunctionReturn(0);
8353 }
8354 
8355 #undef __FUNCT__
8356 #define __FUNCT__ "DMPlexGetCones"
8357 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8358 {
8359   DM_Plex *mesh = (DM_Plex*) dm->data;
8360 
8361   PetscFunctionBegin;
8362   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8363   if (cones) *cones = mesh->cones;
8364   PetscFunctionReturn(0);
8365 }
8366 
8367 #undef __FUNCT__
8368 #define __FUNCT__ "DMPlexGetConeOrientations"
8369 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8370 {
8371   DM_Plex *mesh = (DM_Plex*) dm->data;
8372 
8373   PetscFunctionBegin;
8374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8375   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8376   PetscFunctionReturn(0);
8377 }
8378 
8379 #undef __FUNCT__
8380 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8381 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8382 {
8383   const PetscInt embedDim = 2;
8384   PetscReal      x        = PetscRealPart(point[0]);
8385   PetscReal      y        = PetscRealPart(point[1]);
8386   PetscReal      v0[2], J[4], invJ[4], detJ;
8387   PetscReal      xi, eta;
8388   PetscErrorCode ierr;
8389 
8390   PetscFunctionBegin;
8391   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8392   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8393   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8394 
8395   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) *cell = c;
8396   else *cell = -1;
8397   PetscFunctionReturn(0);
8398 }
8399 
8400 #undef __FUNCT__
8401 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8402 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8403 {
8404   PetscSection      coordSection;
8405   Vec               coordsLocal;
8406   const PetscScalar *coords;
8407   const PetscInt    faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8408   PetscReal         x         = PetscRealPart(point[0]);
8409   PetscReal         y         = PetscRealPart(point[1]);
8410   PetscInt          crossings = 0, f;
8411   PetscErrorCode    ierr;
8412 
8413   PetscFunctionBegin;
8414   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8415   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8416   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8417   for (f = 0; f < 4; ++f) {
8418     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8419     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8420     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8421     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8422     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8423     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8424     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8425     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8426     if ((cond1 || cond2)  && above) ++crossings;
8427   }
8428   if (crossings % 2) *cell = c;
8429   else *cell = -1;
8430   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8431   PetscFunctionReturn(0);
8432 }
8433 
8434 #undef __FUNCT__
8435 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8436 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8437 {
8438   const PetscInt embedDim = 3;
8439   PetscReal      v0[3], J[9], invJ[9], detJ;
8440   PetscReal      x = PetscRealPart(point[0]);
8441   PetscReal      y = PetscRealPart(point[1]);
8442   PetscReal      z = PetscRealPart(point[2]);
8443   PetscReal      xi, eta, zeta;
8444   PetscErrorCode ierr;
8445 
8446   PetscFunctionBegin;
8447   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8448   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8449   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8450   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8451 
8452   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) *cell = c;
8453   else *cell = -1;
8454   PetscFunctionReturn(0);
8455 }
8456 
8457 #undef __FUNCT__
8458 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8459 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8460 {
8461   PetscSection      coordSection;
8462   Vec               coordsLocal;
8463   const PetscScalar *coords;
8464   const PetscInt    faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8465                                  3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8466   PetscBool         found = PETSC_TRUE;
8467   PetscInt          f;
8468   PetscErrorCode    ierr;
8469 
8470   PetscFunctionBegin;
8471   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8472   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8473   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8474   for (f = 0; f < 6; ++f) {
8475     /* Check the point is under plane */
8476     /*   Get face normal */
8477     PetscReal v_i[3];
8478     PetscReal v_j[3];
8479     PetscReal normal[3];
8480     PetscReal pp[3];
8481     PetscReal dot;
8482 
8483     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8484     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8485     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8486     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8487     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8488     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8489     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8490     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8491     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8492     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8493     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8494     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8495     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8496 
8497     /* Check that projected point is in face (2D location problem) */
8498     if (dot < 0.0) {
8499       found = PETSC_FALSE;
8500       break;
8501     }
8502   }
8503   if (found) *cell = c;
8504   else *cell = -1;
8505   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8506   PetscFunctionReturn(0);
8507 }
8508 
8509 #undef __FUNCT__
8510 #define __FUNCT__ "DMLocatePoints_Plex"
8511 /*
8512  Need to implement using the guess
8513 */
8514 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8515 {
8516   PetscInt       cell = -1 /*, guess = -1*/;
8517   PetscInt       bs, numPoints, p;
8518   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8519   PetscInt       *cells;
8520   PetscScalar    *a;
8521   PetscErrorCode ierr;
8522 
8523   PetscFunctionBegin;
8524   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8525   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8526   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8527   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
8528   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8529   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8530   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8531   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);
8532   numPoints /= bs;
8533   ierr       = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8534   for (p = 0; p < numPoints; ++p) {
8535     const PetscScalar *point = &a[p*bs];
8536 
8537     switch (dim) {
8538     case 2:
8539       for (c = cStart; c < cEnd; ++c) {
8540         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8541         switch (coneSize) {
8542         case 3:
8543           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8544           break;
8545         case 4:
8546           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8547           break;
8548         default:
8549           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8550         }
8551         if (cell >= 0) break;
8552       }
8553       break;
8554     case 3:
8555       for (c = cStart; c < cEnd; ++c) {
8556         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8557         switch (coneSize) {
8558         case 4:
8559           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8560           break;
8561         case 8:
8562           ierr = DMPlexLocatePoint_General_3D(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     default:
8571       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8572     }
8573     cells[p] = cell;
8574   }
8575   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8576   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8577   PetscFunctionReturn(0);
8578 }
8579 
8580 /******************************** FEM Support **********************************/
8581 
8582 #undef __FUNCT__
8583 #define __FUNCT__ "DMPlexVecGetClosure"
8584 /*@C
8585   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8586 
8587   Not collective
8588 
8589   Input Parameters:
8590 + dm - The DM
8591 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8592 . v - The local vector
8593 - point - The sieve point in the DM
8594 
8595   Output Parameters:
8596 + csize - The number of values in the closure, or PETSC_NULL
8597 - values - The array of values, which is a borrowed array and should not be freed
8598 
8599   Level: intermediate
8600 
8601 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8602 @*/
8603 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8604 {
8605   PetscScalar    *array, *vArray;
8606   PetscInt       *points = PETSC_NULL;
8607   PetscInt       offsets[32];
8608   PetscInt       numFields, size, numPoints, pStart, pEnd, p, q, f;
8609   PetscErrorCode ierr;
8610 
8611   PetscFunctionBegin;
8612   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8613   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8614   if (!section) {
8615     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8616   }
8617   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8618   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8619   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8620   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8621   /* Compress out points not in the section */
8622   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8623   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8624     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8625       points[q*2]   = points[p];
8626       points[q*2+1] = points[p+1];
8627       ++q;
8628     }
8629   }
8630   numPoints = q;
8631   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8632     PetscInt dof, fdof;
8633 
8634     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8635     for (f = 0; f < numFields; ++f) {
8636       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8637       offsets[f+1] += fdof;
8638     }
8639     size += dof;
8640   }
8641   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8642   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8643   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8644   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8645   for (p = 0; p < numPoints*2; p += 2) {
8646     PetscInt    o = points[p+1];
8647     PetscInt    dof, off, d;
8648     PetscScalar *varr;
8649 
8650     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8651     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8652     varr = &vArray[off];
8653     if (numFields) {
8654       PetscInt fdof, foff, fcomp, f, c;
8655 
8656       for (f = 0, foff = 0; f < numFields; ++f) {
8657         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8658         if (o >= 0) {
8659           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8660             array[offsets[f]] = varr[foff+d];
8661           }
8662         } else {
8663           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8664           for (d = fdof/fcomp-1; d >= 0; --d) {
8665             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8666               array[offsets[f]] = varr[foff+d*fcomp+c];
8667             }
8668           }
8669         }
8670         foff += fdof;
8671       }
8672     } else {
8673       if (o >= 0) {
8674         for (d = 0; d < dof; ++d, ++offsets[0]) {
8675           array[offsets[0]] = varr[d];
8676         }
8677       } else {
8678         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8679           array[offsets[0]] = varr[d];
8680         }
8681       }
8682     }
8683   }
8684   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8685   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8686   if (csize) *csize = size;
8687   *values = array;
8688   PetscFunctionReturn(0);
8689 }
8690 
8691 #undef __FUNCT__
8692 #define __FUNCT__ "DMPlexVecRestoreClosure"
8693 /*@C
8694   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8695 
8696   Not collective
8697 
8698   Input Parameters:
8699 + dm - The DM
8700 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8701 . v - The local vector
8702 . point - The sieve point in the DM
8703 . csize - The number of values in the closure, or PETSC_NULL
8704 - values - The array of values, which is a borrowed array and should not be freed
8705 
8706   Level: intermediate
8707 
8708 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8709 @*/
8710 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8711 {
8712   PetscInt       size = 0;
8713   PetscErrorCode ierr;
8714 
8715   PetscFunctionBegin;
8716   /* Should work without recalculating size */
8717   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void*) values);CHKERRQ(ierr);
8718   PetscFunctionReturn(0);
8719 }
8720 
8721 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8722 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8723 
8724 #undef __FUNCT__
8725 #define __FUNCT__ "updatePoint_private"
8726 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8727 {
8728   PetscInt       cdof;   /* The number of constraints on this point */
8729   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8730   PetscScalar    *a;
8731   PetscInt       off, cind = 0, k;
8732   PetscErrorCode ierr;
8733 
8734   PetscFunctionBegin;
8735   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8736   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8737   a    = &array[off];
8738   if (!cdof || setBC) {
8739     if (orientation >= 0) {
8740       for (k = 0; k < dof; ++k) {
8741         fuse(&a[k], values[k]);
8742       }
8743     } else {
8744       for (k = 0; k < dof; ++k) {
8745         fuse(&a[k], values[dof-k-1]);
8746       }
8747     }
8748   } else {
8749     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8750     if (orientation >= 0) {
8751       for (k = 0; k < dof; ++k) {
8752         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8753         fuse(&a[k], values[k]);
8754       }
8755     } else {
8756       for (k = 0; k < dof; ++k) {
8757         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8758         fuse(&a[k], values[dof-k-1]);
8759       }
8760     }
8761   }
8762   PetscFunctionReturn(0);
8763 }
8764 
8765 #undef __FUNCT__
8766 #define __FUNCT__ "updatePointFields_private"
8767 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar*, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8768 {
8769   PetscScalar    *a;
8770   PetscInt       numFields, off, foff, f;
8771   PetscErrorCode ierr;
8772 
8773   PetscFunctionBegin;
8774   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8775   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8776   a    = &array[off];
8777   for (f = 0, foff = 0; f < numFields; ++f) {
8778     PetscInt       fdof, fcomp, fcdof;
8779     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8780     PetscInt       cind = 0, k, c;
8781 
8782     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8783     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8784     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8785     if (!fcdof || setBC) {
8786       if (orientation >= 0) {
8787         for (k = 0; k < fdof; ++k) {
8788           fuse(&a[foff+k], values[foffs[f]+k]);
8789         }
8790       } else {
8791         for (k = fdof/fcomp-1; k >= 0; --k) {
8792           for (c = 0; c < fcomp; ++c) {
8793             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8794           }
8795         }
8796       }
8797     } else {
8798       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8799       if (orientation >= 0) {
8800         for (k = 0; k < fdof; ++k) {
8801           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8802           fuse(&a[foff+k], values[foffs[f]+k]);
8803         }
8804       } else {
8805         for (k = fdof/fcomp-1; k >= 0; --k) {
8806           for (c = 0; c < fcomp; ++c) {
8807             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8808             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8809           }
8810         }
8811       }
8812     }
8813     foff     += fdof;
8814     foffs[f] += fdof;
8815   }
8816   PetscFunctionReturn(0);
8817 }
8818 
8819 #undef __FUNCT__
8820 #define __FUNCT__ "DMPlexVecSetClosure"
8821 /*@C
8822   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8823 
8824   Not collective
8825 
8826   Input Parameters:
8827 + dm - The DM
8828 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8829 . v - The local vector
8830 . point - The sieve point in the DM
8831 . values - The array of values, which is a borrowed array and should not be freed
8832 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8833 
8834   Level: intermediate
8835 
8836 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8837 @*/
8838 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8839 {
8840   PetscScalar    *array;
8841   PetscInt       *points = PETSC_NULL;
8842   PetscInt       offsets[32];
8843   PetscInt       numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8844   PetscErrorCode ierr;
8845 
8846   PetscFunctionBegin;
8847   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8848   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8849   if (!section) {
8850     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8851   }
8852   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8853   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8854   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8855   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8856   /* Compress out points not in the section */
8857   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8858   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8859     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8860       points[q*2]   = points[p];
8861       points[q*2+1] = points[p+1];
8862       ++q;
8863     }
8864   }
8865   numPoints = q;
8866   for (p = 0; p < numPoints*2; p += 2) {
8867     PetscInt fdof;
8868 
8869     for (f = 0; f < numFields; ++f) {
8870       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8871       offsets[f+1] += fdof;
8872     }
8873   }
8874   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
8875   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8876   if (numFields) {
8877     switch (mode) {
8878     case INSERT_VALUES:
8879       for (p = 0; p < numPoints*2; p += 2) {
8880         PetscInt o = points[p+1];
8881         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8882       } break;
8883     case INSERT_ALL_VALUES:
8884       for (p = 0; p < numPoints*2; p += 2) {
8885         PetscInt o = points[p+1];
8886         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8887       } break;
8888     case ADD_VALUES:
8889       for (p = 0; p < numPoints*2; p += 2) {
8890         PetscInt o = points[p+1];
8891         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8892       } break;
8893     case ADD_ALL_VALUES:
8894       for (p = 0; p < numPoints*2; p += 2) {
8895         PetscInt o = points[p+1];
8896         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8897       } break;
8898     default:
8899       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8900     }
8901   } else {
8902     switch (mode) {
8903     case INSERT_VALUES:
8904       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8905         PetscInt o = points[p+1];
8906         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8907         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8908       } break;
8909     case INSERT_ALL_VALUES:
8910       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8911         PetscInt o = points[p+1];
8912         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8913         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8914       } break;
8915     case ADD_VALUES:
8916       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8917         PetscInt o = points[p+1];
8918         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8919         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8920       } break;
8921     case ADD_ALL_VALUES:
8922       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8923         PetscInt o = points[p+1];
8924         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8925         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8926       } break;
8927     default:
8928       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8929     }
8930   }
8931   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8932   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8933   PetscFunctionReturn(0);
8934 }
8935 
8936 #undef __FUNCT__
8937 #define __FUNCT__ "DMPlexPrintMatSetValues"
8938 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8939 {
8940   PetscMPIInt    rank;
8941   PetscInt       i, j;
8942   PetscErrorCode ierr;
8943 
8944   PetscFunctionBegin;
8945   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8946   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8947   for (i = 0; i < numIndices; i++) {
8948     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8949   }
8950   for (i = 0; i < numIndices; i++) {
8951     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8952     for (j = 0; j < numIndices; j++) {
8953 #if defined(PETSC_USE_COMPLEX)
8954       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8955 #else
8956       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8957 #endif
8958     }
8959     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8960   }
8961   PetscFunctionReturn(0);
8962 }
8963 
8964 #undef __FUNCT__
8965 #define __FUNCT__ "indicesPoint_private"
8966 /* . off - The global offset of this point */
8967 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8968 {
8969   PetscInt       cdof;   /* The number of constraints on this point */
8970   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8971   PetscInt       cind = 0, k;
8972   PetscErrorCode ierr;
8973 
8974   PetscFunctionBegin;
8975   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8976   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8977   if (!cdof || setBC) {
8978     if (orientation >= 0) {
8979       for (k = 0; k < dof; ++k) indices[k] = off+k;
8980     } else {
8981       for (k = 0; k < dof; ++k) indices[dof-k-1] = off+k;
8982     }
8983   } else {
8984     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8985     if (orientation >= 0) {
8986       for (k = 0; k < dof; ++k) {
8987         if ((cind < cdof) && (k == cdofs[cind])) {
8988           /* Insert check for returning constrained indices */
8989           indices[k] = -(off+k+1);
8990           ++cind;
8991         } else {
8992           indices[k] = off+k-cind;
8993         }
8994       }
8995     } else {
8996       for (k = 0; k < dof; ++k) {
8997         if ((cind < cdof) && (k == cdofs[cind])) {
8998           /* Insert check for returning constrained indices */
8999           indices[dof-k-1] = -(off+k+1);
9000           ++cind;
9001         } else {
9002           indices[dof-k-1] = off+k-cind;
9003         }
9004       }
9005     }
9006   }
9007   PetscFunctionReturn(0);
9008 }
9009 
9010 #undef __FUNCT__
9011 #define __FUNCT__ "indicesPointFields_private"
9012 /* . off - The global offset of this point */
9013 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
9014 {
9015   PetscInt       numFields, foff, f;
9016   PetscErrorCode ierr;
9017 
9018   PetscFunctionBegin;
9019   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9020   for (f = 0, foff = 0; f < numFields; ++f) {
9021     PetscInt        fdof, fcomp, cfdof;
9022     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
9023     PetscInt        cind = 0, k, c;
9024 
9025     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
9026     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
9027     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
9028     if (!cfdof || setBC) {
9029       if (orientation >= 0) {
9030         for (k = 0; k < fdof; ++k) indices[foffs[f]+k] = off+foff+k;
9031       } else {
9032         for (k = fdof/fcomp-1; k >= 0; --k) {
9033           for (c = 0; c < fcomp; ++c) {
9034             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
9035           }
9036         }
9037       }
9038     } else {
9039       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
9040       if (orientation >= 0) {
9041         for (k = 0; k < fdof; ++k) {
9042           if ((cind < cfdof) && (k == fcdofs[cind])) {
9043             indices[foffs[f]+k] = -(off+foff+k+1);
9044             ++cind;
9045           } else {
9046             indices[foffs[f]+k] = off+foff+k-cind;
9047           }
9048         }
9049       } else {
9050         for (k = fdof/fcomp-1; k >= 0; --k) {
9051           for (c = 0; c < fcomp; ++c) {
9052             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
9053               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
9054               ++cind;
9055             } else {
9056               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
9057             }
9058           }
9059         }
9060       }
9061     }
9062     foff     += fdof - cfdof;
9063     foffs[f] += fdof;
9064   }
9065   PetscFunctionReturn(0);
9066 }
9067 
9068 #undef __FUNCT__
9069 #define __FUNCT__ "DMPlexMatSetClosure"
9070 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
9071 {
9072   DM_Plex        *mesh   = (DM_Plex*) dm->data;
9073   PetscInt       *points = PETSC_NULL;
9074   PetscInt       *indices;
9075   PetscInt       offsets[32];
9076   PetscInt       numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
9077   PetscBool      useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
9078   PetscBool      useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
9079   PetscErrorCode ierr;
9080 
9081   PetscFunctionBegin;
9082   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9083   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
9084   if (useDefault) {
9085     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9086   }
9087   if (useGlobalDefault) {
9088     if (useDefault) {
9089       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
9090     } else {
9091       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9092     }
9093   }
9094   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9095   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
9096   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
9097   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9098   /* Compress out points not in the section */
9099   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
9100   for (p = 0, q = 0; p < numPoints*2; p += 2) {
9101     if ((points[p] >= pStart) && (points[p] < pEnd)) {
9102       points[q*2]   = points[p];
9103       points[q*2+1] = points[p+1];
9104       ++q;
9105     }
9106   }
9107   numPoints = q;
9108   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
9109     PetscInt fdof;
9110 
9111     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
9112     for (f = 0; f < numFields; ++f) {
9113       ierr          = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
9114       offsets[f+1] += fdof;
9115     }
9116     numIndices += dof;
9117   }
9118   for (f = 1; f < numFields; ++f) offsets[f+1] += offsets[f];
9119 
9120   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
9121   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9122   if (numFields) {
9123     for (p = 0; p < numPoints*2; p += 2) {
9124       PetscInt o = points[p+1];
9125       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9126       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
9127     }
9128   } else {
9129     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
9130       PetscInt o = points[p+1];
9131       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9132       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
9133     }
9134   }
9135   if (useGlobalDefault && !useDefault) {
9136     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9137   }
9138   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
9139   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9140   if (ierr) {
9141     PetscMPIInt    rank;
9142     PetscErrorCode ierr2;
9143 
9144     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
9145     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9146     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9147     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9148     CHKERRQ(ierr);
9149   }
9150   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9151   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9152   PetscFunctionReturn(0);
9153 }
9154 
9155 #undef __FUNCT__
9156 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9157 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9158 {
9159   PetscSection      coordSection;
9160   Vec               coordinates;
9161   const PetscScalar *coords;
9162   const PetscInt    dim = 2;
9163   PetscInt          d, f;
9164   PetscErrorCode    ierr;
9165 
9166   PetscFunctionBegin;
9167   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9168   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9169   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9170   if (v0) {
9171     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9172   }
9173   if (J) {
9174     for (d = 0; d < dim; d++) {
9175       for (f = 0; f < dim; f++) {
9176         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9177       }
9178     }
9179     *detJ = J[0]*J[3] - J[1]*J[2];
9180 #if 0
9181     if (detJ < 0.0) {
9182       const PetscReal xLength = mesh->periodicity[0];
9183 
9184       if (xLength != 0.0) {
9185         PetscReal v0x = coords[0*dim+0];
9186 
9187         if (v0x == 0.0) v0x = v0[0] = xLength;
9188         for (f = 0; f < dim; f++) {
9189           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9190 
9191           J[0*dim+f] = 0.5*(px - v0x);
9192         }
9193       }
9194       detJ = J[0]*J[3] - J[1]*J[2];
9195     }
9196 #endif
9197     PetscLogFlops(8.0 + 3.0);
9198   }
9199   if (invJ) {
9200     const PetscReal invDet = 1.0/(*detJ);
9201 
9202     invJ[0] =  invDet*J[3];
9203     invJ[1] = -invDet*J[1];
9204     invJ[2] = -invDet*J[2];
9205     invJ[3] =  invDet*J[0];
9206     PetscLogFlops(5.0);
9207   }
9208   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9209   PetscFunctionReturn(0);
9210 }
9211 
9212 #undef __FUNCT__
9213 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9214 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9215 {
9216   PetscSection      coordSection;
9217   Vec               coordinates;
9218   const PetscScalar *coords;
9219   const PetscInt    dim = 2;
9220   PetscInt          d, f;
9221   PetscErrorCode    ierr;
9222 
9223   PetscFunctionBegin;
9224   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9225   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9226   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9227   if (v0) {
9228     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9229   }
9230   if (J) {
9231     for (d = 0; d < dim; d++) {
9232       for (f = 0; f < dim; f++) {
9233         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9234       }
9235     }
9236     *detJ = J[0]*J[3] - J[1]*J[2];
9237     PetscLogFlops(8.0 + 3.0);
9238   }
9239   if (invJ) {
9240     const PetscReal invDet = 1.0/(*detJ);
9241 
9242     invJ[0] =  invDet*J[3];
9243     invJ[1] = -invDet*J[1];
9244     invJ[2] = -invDet*J[2];
9245     invJ[3] =  invDet*J[0];
9246     PetscLogFlops(5.0);
9247   }
9248   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9249   PetscFunctionReturn(0);
9250 }
9251 
9252 #undef __FUNCT__
9253 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9254 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9255 {
9256   PetscSection      coordSection;
9257   Vec               coordinates;
9258   const PetscScalar *coords;
9259   const PetscInt    dim = 3;
9260   PetscInt          d, f;
9261   PetscErrorCode    ierr;
9262 
9263   PetscFunctionBegin;
9264   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9265   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9266   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9267   if (v0) {
9268     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9269   }
9270   if (J) {
9271     for (d = 0; d < dim; d++) {
9272       for (f = 0; f < dim; f++) {
9273         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9274       }
9275     }
9276     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9277     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9278              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9279              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9280     PetscLogFlops(18.0 + 12.0);
9281   }
9282   if (invJ) {
9283     const PetscReal invDet = 1.0/(*detJ);
9284 
9285     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9286     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9287     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9288     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9289     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9290     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9291     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9292     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9293     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9294     PetscLogFlops(37.0);
9295   }
9296   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9297   PetscFunctionReturn(0);
9298 }
9299 
9300 #undef __FUNCT__
9301 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9302 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9303 {
9304   PetscSection      coordSection;
9305   Vec               coordinates;
9306   const PetscScalar *coords;
9307   const PetscInt    dim = 3;
9308   PetscInt          d;
9309   PetscErrorCode    ierr;
9310 
9311   PetscFunctionBegin;
9312   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9313   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9314   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9315   if (v0) {
9316     for (d = 0; d < dim; d++) v0[d] = PetscRealPart(coords[d]);
9317   }
9318   if (J) {
9319     for (d = 0; d < dim; d++) {
9320       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9321       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9322       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9323     }
9324     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9325              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9326              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9327     PetscLogFlops(18.0 + 12.0);
9328   }
9329   if (invJ) {
9330     const PetscReal invDet = -1.0/(*detJ);
9331 
9332     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9333     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9334     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9335     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9336     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9337     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9338     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9339     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9340     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9341     PetscLogFlops(37.0);
9342   }
9343   *detJ *= 8.0;
9344   ierr   = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9345   PetscFunctionReturn(0);
9346 }
9347 
9348 #undef __FUNCT__
9349 #define __FUNCT__ "DMPlexComputeCellGeometry"
9350 /*@C
9351   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9352 
9353   Collective on DM
9354 
9355   Input Arguments:
9356 + dm   - the DM
9357 - cell - the cell
9358 
9359   Output Arguments:
9360 + v0   - the translation part of this affine transform
9361 . J    - the Jacobian of the transform to the reference element
9362 . invJ - the inverse of the Jacobian
9363 - detJ - the Jacobian determinant
9364 
9365   Level: advanced
9366 
9367 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9368 @*/
9369 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9370 {
9371   PetscInt       dim, coneSize;
9372   PetscErrorCode ierr;
9373 
9374   PetscFunctionBegin;
9375   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9376   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9377   switch (dim) {
9378   case 2:
9379     switch (coneSize) {
9380     case 3:
9381       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9382       break;
9383     case 4:
9384       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9385       break;
9386     default:
9387       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9388     }
9389     break;
9390   case 3:
9391     switch (coneSize) {
9392     case 4:
9393       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9394       break;
9395     case 8:
9396       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9397       break;
9398     default:
9399       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9400     }
9401     break;
9402   default:
9403     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9404   }
9405   PetscFunctionReturn(0);
9406 }
9407 
9408 #undef __FUNCT__
9409 #define __FUNCT__ "DMPlexGetFaceOrientation"
9410 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9411 {
9412   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9413   PetscBool      posOrient = PETSC_FALSE;
9414   const PetscInt debug     = 0;
9415   PetscInt       cellDim, faceSize, f;
9416   PetscErrorCode ierr;
9417 
9418   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9419   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9420 
9421   if (cellDim == numCorners-1) {
9422     /* Simplices */
9423     faceSize  = numCorners-1;
9424     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9425   } else if (cellDim == 1 && numCorners == 3) {
9426     /* Quadratic line */
9427     faceSize  = 1;
9428     posOrient = PETSC_TRUE;
9429   } else if (cellDim == 2 && numCorners == 4) {
9430     /* Quads */
9431     faceSize = 2;
9432     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9433       posOrient = PETSC_TRUE;
9434     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9435       posOrient = PETSC_TRUE;
9436     } else {
9437       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9438         posOrient = PETSC_FALSE;
9439       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9440     }
9441   } else if (cellDim == 2 && numCorners == 6) {
9442     /* Quadratic triangle (I hate this) */
9443     /* Edges are determined by the first 2 vertices (corners of edges) */
9444     const PetscInt faceSizeTri = 3;
9445     PetscInt       sortedIndices[3], i, iFace;
9446     PetscBool      found                    = PETSC_FALSE;
9447     PetscInt       faceVerticesTriSorted[9] = {
9448       0, 3,  4, /* bottom */
9449       1, 4,  5, /* right */
9450       2, 3,  5, /* left */
9451     };
9452     PetscInt       faceVerticesTri[9] = {
9453       0, 3,  4, /* bottom */
9454       1, 4,  5, /* right */
9455       2, 5,  3, /* left */
9456     };
9457 
9458     faceSize = faceSizeTri;
9459     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9460     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9461     for (iFace = 0; iFace < 3; ++iFace) {
9462       const PetscInt ii = iFace*faceSizeTri;
9463       PetscInt       fVertex, cVertex;
9464 
9465       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9466           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9467         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9468           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9469             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9470               faceVertices[fVertex] = origVertices[cVertex];
9471               break;
9472             }
9473           }
9474         }
9475         found = PETSC_TRUE;
9476         break;
9477       }
9478     }
9479     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9480     if (posOriented) *posOriented = PETSC_TRUE;
9481     PetscFunctionReturn(0);
9482   } else if (cellDim == 2 && numCorners == 9) {
9483     /* Quadratic quad (I hate this) */
9484     /* Edges are determined by the first 2 vertices (corners of edges) */
9485     const PetscInt faceSizeQuad = 3;
9486     PetscInt       sortedIndices[3], i, iFace;
9487     PetscBool      found                      = PETSC_FALSE;
9488     PetscInt       faceVerticesQuadSorted[12] = {
9489       0, 1,  4, /* bottom */
9490       1, 2,  5, /* right */
9491       2, 3,  6, /* top */
9492       0, 3,  7, /* left */
9493     };
9494     PetscInt       faceVerticesQuad[12] = {
9495       0, 1,  4, /* bottom */
9496       1, 2,  5, /* right */
9497       2, 3,  6, /* top */
9498       3, 0,  7, /* left */
9499     };
9500 
9501     faceSize = faceSizeQuad;
9502     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9503     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9504     for (iFace = 0; iFace < 4; ++iFace) {
9505       const PetscInt ii = iFace*faceSizeQuad;
9506       PetscInt       fVertex, cVertex;
9507 
9508       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9509           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9510         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9511           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9512             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9513               faceVertices[fVertex] = origVertices[cVertex];
9514               break;
9515             }
9516           }
9517         }
9518         found = PETSC_TRUE;
9519         break;
9520       }
9521     }
9522     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9523     if (posOriented) *posOriented = PETSC_TRUE;
9524     PetscFunctionReturn(0);
9525   } else if (cellDim == 3 && numCorners == 8) {
9526     /* Hexes
9527        A hex is two oriented quads with the normal of the first
9528        pointing up at the second.
9529 
9530           7---6
9531          /|  /|
9532         4---5 |
9533         | 3-|-2
9534         |/  |/
9535         0---1
9536 
9537         Faces are determined by the first 4 vertices (corners of faces) */
9538     const PetscInt faceSizeHex = 4;
9539     PetscInt       sortedIndices[4], i, iFace;
9540     PetscBool      found                     = PETSC_FALSE;
9541     PetscInt       faceVerticesHexSorted[24] = {
9542       0, 1, 2, 3,  /* bottom */
9543       4, 5, 6, 7,  /* top */
9544       0, 1, 4, 5,  /* front */
9545       1, 2, 5, 6,  /* right */
9546       2, 3, 6, 7,  /* back */
9547       0, 3, 4, 7,  /* left */
9548     };
9549     PetscInt       faceVerticesHex[24] = {
9550       3, 2, 1, 0,  /* bottom */
9551       4, 5, 6, 7,  /* top */
9552       0, 1, 5, 4,  /* front */
9553       1, 2, 6, 5,  /* right */
9554       2, 3, 7, 6,  /* back */
9555       3, 0, 4, 7,  /* left */
9556     };
9557 
9558     faceSize = faceSizeHex;
9559     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9560     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9561     for (iFace = 0; iFace < 6; ++iFace) {
9562       const PetscInt ii = iFace*faceSizeHex;
9563       PetscInt       fVertex, cVertex;
9564 
9565       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9566           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9567           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9568           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9569         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9570           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9571             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9572               faceVertices[fVertex] = origVertices[cVertex];
9573               break;
9574             }
9575           }
9576         }
9577         found = PETSC_TRUE;
9578         break;
9579       }
9580     }
9581     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9582     if (posOriented) *posOriented = PETSC_TRUE;
9583     PetscFunctionReturn(0);
9584   } else if (cellDim == 3 && numCorners == 10) {
9585     /* Quadratic tet */
9586     /* Faces are determined by the first 3 vertices (corners of faces) */
9587     const PetscInt faceSizeTet = 6;
9588     PetscInt       sortedIndices[6], i, iFace;
9589     PetscBool      found                     = PETSC_FALSE;
9590     PetscInt       faceVerticesTetSorted[24] = {
9591       0, 1, 2,  6, 7, 8, /* bottom */
9592       0, 3, 4,  6, 7, 9,  /* front */
9593       1, 4, 5,  7, 8, 9,  /* right */
9594       2, 3, 5,  6, 8, 9,  /* left */
9595     };
9596     PetscInt       faceVerticesTet[24] = {
9597       0, 1, 2,  6, 7, 8, /* bottom */
9598       0, 4, 3,  6, 7, 9,  /* front */
9599       1, 5, 4,  7, 8, 9,  /* right */
9600       2, 3, 5,  8, 6, 9,  /* left */
9601     };
9602 
9603     faceSize = faceSizeTet;
9604     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9605     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9606     for (iFace=0; iFace < 4; ++iFace) {
9607       const PetscInt ii = iFace*faceSizeTet;
9608       PetscInt       fVertex, cVertex;
9609 
9610       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9611           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9612           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9613           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9614         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9615           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9616             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9617               faceVertices[fVertex] = origVertices[cVertex];
9618               break;
9619             }
9620           }
9621         }
9622         found = PETSC_TRUE;
9623         break;
9624       }
9625     }
9626     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9627     if (posOriented) *posOriented = PETSC_TRUE;
9628     PetscFunctionReturn(0);
9629   } else if (cellDim == 3 && numCorners == 27) {
9630     /* Quadratic hexes (I hate this)
9631        A hex is two oriented quads with the normal of the first
9632        pointing up at the second.
9633 
9634          7---6
9635         /|  /|
9636        4---5 |
9637        | 3-|-2
9638        |/  |/
9639        0---1
9640 
9641        Faces are determined by the first 4 vertices (corners of faces) */
9642     const PetscInt faceSizeQuadHex = 9;
9643     PetscInt       sortedIndices[9], i, iFace;
9644     PetscBool      found                         = PETSC_FALSE;
9645     PetscInt       faceVerticesQuadHexSorted[54] = {
9646       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9647       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9648       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9649       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9650       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9651       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9652     };
9653     PetscInt       faceVerticesQuadHex[54] = {
9654       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9655       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9656       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9657       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9658       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9659       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9660     };
9661 
9662     faceSize = faceSizeQuadHex;
9663     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9664     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9665     for (iFace = 0; iFace < 6; ++iFace) {
9666       const PetscInt ii = iFace*faceSizeQuadHex;
9667       PetscInt       fVertex, cVertex;
9668 
9669       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9670           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9671           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9672           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9673         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9674           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9675             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9676               faceVertices[fVertex] = origVertices[cVertex];
9677               break;
9678             }
9679           }
9680         }
9681         found = PETSC_TRUE;
9682         break;
9683       }
9684     }
9685     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9686     if (posOriented) *posOriented = PETSC_TRUE;
9687     PetscFunctionReturn(0);
9688   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9689   if (!posOrient) {
9690     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9691     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[faceSize-1 - f];
9692   } else {
9693     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9694     for (f = 0; f < faceSize; ++f) faceVertices[f] = origVertices[f];
9695   }
9696   if (posOriented) *posOriented = posOrient;
9697   PetscFunctionReturn(0);
9698 }
9699 
9700 #undef __FUNCT__
9701 #define __FUNCT__ "DMPlexGetOrientedFace"
9702 /*
9703     Given a cell and a face, as a set of vertices,
9704       return the oriented face, as a set of vertices, in faceVertices
9705     The orientation is such that the face normal points out of the cell
9706 */
9707 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9708 {
9709   const PetscInt *cone = PETSC_NULL;
9710   PetscInt       coneSize, v, f, v2;
9711   PetscInt       oppositeVertex = -1;
9712   PetscErrorCode ierr;
9713 
9714   PetscFunctionBegin;
9715   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9716   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9717   for (v = 0, v2 = 0; v < coneSize; ++v) {
9718     PetscBool found = PETSC_FALSE;
9719 
9720     for (f = 0; f < faceSize; ++f) {
9721       if (face[f] == cone[v]) {
9722         found = PETSC_TRUE; break;
9723       }
9724     }
9725     if (found) {
9726       indices[v2]      = v;
9727       origVertices[v2] = cone[v];
9728       ++v2;
9729     } else {
9730       oppositeVertex = v;
9731     }
9732   }
9733   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9734   PetscFunctionReturn(0);
9735 }
9736 
9737 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9738 {
9739   switch (i) {
9740   case 0:
9741     switch (j) {
9742     case 0: return 0;
9743     case 1:
9744       switch (k) {
9745       case 0: return 0;
9746       case 1: return 0;
9747       case 2: return 1;
9748       }
9749     case 2:
9750       switch (k) {
9751       case 0: return 0;
9752       case 1: return -1;
9753       case 2: return 0;
9754       }
9755     }
9756   case 1:
9757     switch (j) {
9758     case 0:
9759       switch (k) {
9760       case 0: return 0;
9761       case 1: return 0;
9762       case 2: return -1;
9763       }
9764     case 1: return 0;
9765     case 2:
9766       switch (k) {
9767       case 0: return 1;
9768       case 1: return 0;
9769       case 2: return 0;
9770       }
9771     }
9772   case 2:
9773     switch (j) {
9774     case 0:
9775       switch (k) {
9776       case 0: return 0;
9777       case 1: return 1;
9778       case 2: return 0;
9779       }
9780     case 1:
9781       switch (k) {
9782       case 0: return -1;
9783       case 1: return 0;
9784       case 2: return 0;
9785       }
9786     case 2: return 0;
9787     }
9788   }
9789   return 0;
9790 }
9791 
9792 #undef __FUNCT__
9793 #define __FUNCT__ "DMPlexCreateRigidBody"
9794 /*@C
9795   DMPlexCreateRigidBody - create rigid body modes from coordinates
9796 
9797   Collective on DM
9798 
9799   Input Arguments:
9800 + dm - the DM
9801 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9802 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9803 
9804   Output Argument:
9805 . sp - the null space
9806 
9807   Note: This is necessary to take account of Dirichlet conditions on the displacements
9808 
9809   Level: advanced
9810 
9811 .seealso: MatNullSpaceCreate()
9812 @*/
9813 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9814 {
9815   MPI_Comm       comm = ((PetscObject) dm)->comm;
9816   Vec            coordinates, localMode, mode[6];
9817   PetscSection   coordSection;
9818   PetscScalar    *coords;
9819   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9820   PetscErrorCode ierr;
9821 
9822   PetscFunctionBegin;
9823   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9824   if (dim == 1) {
9825     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9826     PetscFunctionReturn(0);
9827   }
9828   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9829   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9830   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9831   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9832   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9833   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9834   m    = (dim*(dim+1))/2;
9835   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9836   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9837   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9838   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9839   /* Assume P1 */
9840   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9841   for (d = 0; d < dim; ++d) {
9842     PetscScalar values[3] = {0.0, 0.0, 0.0};
9843 
9844     values[d] = 1.0;
9845     ierr      = VecSet(localMode, 0.0);CHKERRQ(ierr);
9846     for (v = vStart; v < vEnd; ++v) {
9847       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9848     }
9849     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9850     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9851   }
9852   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9853   for (d = dim; d < dim*(dim+1)/2; ++d) {
9854     PetscInt i, j, k = dim > 2 ? d - dim : d;
9855 
9856     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9857     for (v = vStart; v < vEnd; ++v) {
9858       PetscScalar values[3] = {0.0, 0.0, 0.0};
9859       PetscInt    off;
9860 
9861       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9862       for (i = 0; i < dim; ++i) {
9863         for (j = 0; j < dim; ++j) {
9864           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9865         }
9866       }
9867       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9868     }
9869     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9870     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9871   }
9872   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9873   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9874   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9875   /* Orthonormalize system */
9876   for (i = dim; i < m; ++i) {
9877     PetscScalar dots[6];
9878 
9879     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9880     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9881     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9882     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9883   }
9884   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9885   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9886   PetscFunctionReturn(0);
9887 }
9888 
9889 #undef __FUNCT__
9890 #define __FUNCT__ "DMPlexGetHybridBounds"
9891 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9892 {
9893   DM_Plex        *mesh = (DM_Plex*) dm->data;
9894   PetscInt       dim;
9895   PetscErrorCode ierr;
9896 
9897   PetscFunctionBegin;
9898   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9899   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9900   if (cMax) *cMax = mesh->hybridPointMax[dim];
9901   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9902   if (eMax) *eMax = mesh->hybridPointMax[1];
9903   if (vMax) *vMax = mesh->hybridPointMax[0];
9904   PetscFunctionReturn(0);
9905 }
9906 
9907 #undef __FUNCT__
9908 #define __FUNCT__ "DMPlexSetHybridBounds"
9909 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9910 {
9911   DM_Plex        *mesh = (DM_Plex*) dm->data;
9912   PetscInt       dim;
9913   PetscErrorCode ierr;
9914 
9915   PetscFunctionBegin;
9916   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9917   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9918   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9919   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9920   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9921   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9922   PetscFunctionReturn(0);
9923 }
9924 
9925 #undef __FUNCT__
9926 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9927 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9928 {
9929   DM_Plex *mesh = (DM_Plex*) dm->data;
9930 
9931   PetscFunctionBegin;
9932   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9933   PetscValidPointer(cellHeight, 2);
9934   *cellHeight = mesh->vtkCellHeight;
9935   PetscFunctionReturn(0);
9936 }
9937 
9938 #undef __FUNCT__
9939 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9940 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9941 {
9942   DM_Plex *mesh = (DM_Plex*) dm->data;
9943 
9944   PetscFunctionBegin;
9945   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9946   mesh->vtkCellHeight = cellHeight;
9947   PetscFunctionReturn(0);
9948 }
9949 
9950 #undef __FUNCT__
9951 #define __FUNCT__ "DMPlexInsertFace_Private"
9952 /*
9953   DMPlexInsertFace_Private - Puts a face into the mesh
9954 
9955   Not collective
9956 
9957   Input Parameters:
9958   + dm              - The DMPlex
9959   . numFaceVertex   - The number of vertices in the face
9960   . faceVertices    - The vertices in the face for dm
9961   . subfaceVertices - The vertices in the face for subdm
9962   . numCorners      - The number of vertices in the cell
9963   . cell            - A cell in dm containing the face
9964   . subcell         - A cell in subdm containing the face
9965   . firstFace       - First face in the mesh
9966   - newFacePoint    - Next face in the mesh
9967 
9968   Output Parameters:
9969   . newFacePoint - Contains next face point number on input, updated on output
9970 
9971   Level: developer
9972 */
9973 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)
9974 {
9975   MPI_Comm       comm     = ((PetscObject) dm)->comm;
9976   DM_Plex        *submesh = (DM_Plex*) subdm->data;
9977   const PetscInt *faces;
9978   PetscInt       numFaces, coneSize;
9979   PetscErrorCode ierr;
9980 
9981   PetscFunctionBegin;
9982   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9983   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9984 #if 0
9985   /* Cannot use this because support() has not been constructed yet */
9986   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9987 #else
9988   {
9989     PetscInt f;
9990 
9991     numFaces = 0;
9992     ierr     = DMGetWorkArray(subdm, 1, PETSC_INT, (void**) &faces);CHKERRQ(ierr);
9993     for (f = firstFace; f < *newFacePoint; ++f) {
9994       PetscInt dof, off, d;
9995 
9996       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9997       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9998       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9999       for (d = 0; d < dof; ++d) {
10000         const PetscInt p = submesh->cones[off+d];
10001         PetscInt       v;
10002 
10003         for (v = 0; v < numFaceVertices; ++v) {
10004           if (subfaceVertices[v] == p) break;
10005         }
10006         if (v == numFaceVertices) break;
10007       }
10008       if (d == dof) {
10009         numFaces               = 1;
10010         ((PetscInt*) faces)[0] = f;
10011       }
10012     }
10013   }
10014 #endif
10015   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
10016   else if (numFaces == 1) {
10017     /* Add the other cell neighbor for this face */
10018     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
10019   } else {
10020     PetscInt  *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
10021     PetscBool posOriented;
10022 
10023     ierr                = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10024     origVertices        = &orientedVertices[numFaceVertices];
10025     indices             = &orientedVertices[numFaceVertices*2];
10026     orientedSubVertices = &orientedVertices[numFaceVertices*3];
10027     ierr                = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
10028     /* TODO: I know that routine should return a permutation, not the indices */
10029     for (v = 0; v < numFaceVertices; ++v) {
10030       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
10031       for (ov = 0; ov < numFaceVertices; ++ov) {
10032         if (orientedVertices[ov] == vertex) {
10033           orientedSubVertices[ov] = subvertex;
10034           break;
10035         }
10036       }
10037       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
10038     }
10039     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
10040     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
10041     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10042     ++(*newFacePoint);
10043   }
10044   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10045   PetscFunctionReturn(0);
10046 }
10047 
10048 #undef __FUNCT__
10049 #define __FUNCT__ "DMPlexCreateSubmesh_Uninterpolated"
10050 static PetscErrorCode DMPlexCreateSubmesh_Uninterpolated(DM dm, const char label[], const char surfaceLabel[], DM subdm)
10051 {
10052   MPI_Comm        comm = ((PetscObject) dm)->comm;
10053   PetscBool       boundaryFaces = PETSC_FALSE;
10054   PetscSection    coordSection, subCoordSection;
10055   Vec             coordinates, subCoordinates;
10056   PetscScalar    *coords, *subCoords;
10057   IS              labelIS, subpointMap;
10058   const PetscInt *subVertices;
10059   PetscInt       *subVerticesActive, *tmpPoints;
10060   PetscInt       *subCells = PETSC_NULL;
10061   PetscInt       numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
10062   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
10063   PetscInt       dim;  /* Right now, do not specify dimension */
10064   PetscInt       cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
10065   PetscErrorCode ierr;
10066 
10067   PetscFunctionBegin;
10068   if (surfaceLabel) SETERRQ(comm, PETSC_ERR_SUP, "Yell at me to do this");
10069   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10070   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10071   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10072   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
10073   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10074   if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
10075   if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
10076   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10077   subface = &face[maxConeSize];
10078   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
10079   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
10080   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
10081   maxSubCells = numSubVertices;
10082   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
10083   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
10084   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
10085   for (v = 0; v < numSubVertices; ++v) {
10086     const PetscInt vertex = subVertices[v];
10087     PetscInt       *star  = PETSC_NULL;
10088     PetscInt       starSize, numCells = 0;
10089 
10090     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10091     for (p = 0; p < starSize*2; p += 2) {
10092       const PetscInt point = star[p];
10093       if ((point >= cStart) && (point < cEnd)) star[numCells++] = point;
10094     }
10095     numOldSubCells = numSubCells;
10096     for (c = 0; c < numCells; ++c) {
10097       const PetscInt cell     = star[c];
10098       PetscInt       *closure = PETSC_NULL;
10099       PetscInt       closureSize, numCorners = 0, faceSize = 0;
10100       PetscInt       cellLoc;
10101 
10102       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
10103       if (cellLoc >= 0) continue;
10104       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10105       for (p = 0; p < closureSize*2; p += 2) {
10106         const PetscInt point = closure[p];
10107         if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
10108       }
10109       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
10110       for (corner = 0; corner < numCorners; ++corner) {
10111         const PetscInt cellVertex = closure[corner];
10112         PetscInt       subVertex;
10113 
10114         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
10115         if (subVertex >= 0) { /* contains submesh vertex */
10116           for (i = 0; i < faceSize; ++i) {
10117             if (cellVertex == face[i]) break;
10118           }
10119           if (i == faceSize) {
10120             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
10121             face[faceSize]    = cellVertex;
10122             subface[faceSize] = subVertex;
10123             ++faceSize;
10124           }
10125         }
10126       }
10127       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10128       if (faceSize >= nFV) {
10129         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10130         if (numSubCells >= maxSubCells) {
10131           PetscInt *tmpCells;
10132           maxSubCells *= 2;
10133           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
10134           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
10135           ierr = PetscFree(subCells);CHKERRQ(ierr);
10136 
10137           subCells = tmpCells;
10138         }
10139         /* TOOD: Maybe overestimate then squeeze out empty faces */
10140         if (faceSize > nFV) {
10141           /* TODO: This is tricky. Maybe just add all faces */
10142           numSubFaces++;
10143         } else {
10144           numSubFaces++;
10145         }
10146         for (f = 0; f < faceSize; ++f) subVerticesActive[subface[f]] = 1;
10147         subCells[numSubCells++] = cell;
10148       }
10149     }
10150     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10151     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
10152   }
10153   /* Pick out active subvertices */
10154   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
10155     if (subVerticesActive[v]) {
10156       subVerticesActive[numSubVerticesActive++] = subVertices[v];
10157     }
10158   }
10159   ierr = DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
10160   /* Set cone sizes */
10161   firstSubVertex = numSubCells;
10162   firstSubFace   = numSubCells+numSubVerticesActive;
10163   newFacePoint   = firstSubFace;
10164   for (c = 0; c < numSubCells; ++c) {
10165     ierr = DMPlexSetConeSize(subdm, c, 1);CHKERRQ(ierr);
10166   }
10167   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
10168     ierr = DMPlexSetConeSize(subdm, f, nFV);CHKERRQ(ierr);
10169   }
10170   ierr = DMSetUp(subdm);CHKERRQ(ierr);
10171   /* Create face cones */
10172   for (c = 0; c < numSubCells; ++c) {
10173     const PetscInt cell     = subCells[c];
10174     PetscInt       *closure = PETSC_NULL;
10175     PetscInt       closureSize, numCorners = 0, faceSize = 0;
10176 
10177     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10178     for (p = 0; p < closureSize*2; p += 2) {
10179       const PetscInt point = closure[p];
10180       if ((point >= vStart) && (point < vEnd)) closure[numCorners++] = point;
10181     }
10182     for (corner = 0; corner < numCorners; ++corner) {
10183       const PetscInt cellVertex = closure[corner];
10184       PetscInt       subVertex;
10185 
10186       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
10187       if (subVertex >= 0) { /* contains submesh vertex */
10188         for (i = 0; i < faceSize; ++i) {
10189           if (cellVertex == face[i]) break;
10190         }
10191         if (i == faceSize) {
10192           face[faceSize]    = cellVertex;
10193           subface[faceSize] = numSubCells+subVertex;
10194           ++faceSize;
10195         }
10196       }
10197     }
10198     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10199     if (faceSize >= nFV) {
10200       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10201       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
10202       /*   We have to take all the faces, and discard those in the interior */
10203       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
10204 #if 0
10205       /* This object just calls insert on each face that comes from subsets() */
10206       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
10207       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
10208       PointArray                          faceVec(face->begin(), face->end());
10209 
10210       subsets(faceVec, nFV, inserter);
10211 #endif
10212       ierr = DMPlexInsertFace_Private(dm, subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10213     }
10214   }
10215   ierr = DMPlexSymmetrize(subdm);CHKERRQ(ierr);
10216   ierr = DMPlexStratify(subdm);CHKERRQ(ierr);
10217   /* Build coordinates */
10218   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10219   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10220   ierr = DMPlexGetCoordinateSection(subdm, &subCoordSection);CHKERRQ(ierr);
10221   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10222   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10223     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10224   }
10225   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10226   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10227   ierr = VecCreate(comm, &subCoordinates);CHKERRQ(ierr);
10228   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10229   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10230   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10231   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10232   for (v = 0; v < numSubVerticesActive; ++v) {
10233     const PetscInt vertex    = subVerticesActive[v];
10234     const PetscInt subVertex = firstSubVertex+v;
10235     PetscInt       dof, off, sdof, soff;
10236 
10237     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10238     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10239     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10240     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10241     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10242     for (d = 0; d < dof; ++d) subCoords[soff+d] = coords[off+d];
10243   }
10244   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10245   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10246   ierr = DMSetCoordinatesLocal(subdm, subCoordinates);CHKERRQ(ierr);
10247   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10248 
10249   ierr = DMPlexSetVTKCellHeight(subdm, 1);CHKERRQ(ierr);
10250   /* Create map from submesh points to original mesh points */
10251   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10252   for (c = 0; c < numSubCells; ++c) tmpPoints[c] = subCells[c];
10253   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) tmpPoints[v] = subVerticesActive[v-numSubCells];
10254   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &subpointMap);CHKERRQ(ierr);
10255   ierr = DMPlexSetSubpointMap(subdm, subpointMap);CHKERRQ(ierr);
10256   ierr = ISDestroy(&subpointMap);CHKERRQ(ierr);
10257 
10258   ierr = PetscFree(subCells);CHKERRQ(ierr);
10259   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10260   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10261   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10262   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10263   PetscFunctionReturn(0);
10264 }
10265 
10266 #undef __FUNCT__
10267 #define __FUNCT__ "DMPlexCreateSubmesh_Interpolated"
10268 static PetscErrorCode DMPlexCreateSubmesh_Interpolated(DM dm, const char vertexLabel[], const char surfaceLabel[], DM subdm)
10269 {
10270   MPI_Comm        comm = ((PetscObject) dm)->comm;
10271   const char     *name = surfaceLabel ? surfaceLabel : "submesh_label";
10272   DMLabel         slabel;
10273   IS              subvertexIS, subedgeIS, subfaceIS, subcellIS, subpointMap;
10274   const PetscInt *subVertices, *subEdges, *subFaces, *subCells;
10275   PetscInt       *coneNew;
10276   PetscInt        dim, numSubVerticesInitial, numSubVertices, firstSubVertex, v, numSubEdges = 0, firstSubEdge, e, numSubFaces = 0, firstSubFace, f, numSubCells;
10277   PetscInt        vStart, vEnd, fStart, fEnd;
10278   PetscErrorCode  ierr;
10279 
10280   PetscFunctionBegin;
10281   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10282   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10283   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
10284   ierr = DMPlexCreateLabel(subdm, name);CHKERRQ(ierr);
10285   ierr = DMPlexGetLabel(subdm, name, &slabel);CHKERRQ(ierr);
10286   ierr = DMPlexGetStratumIS(dm, vertexLabel, 1, &subvertexIS);CHKERRQ(ierr);
10287   ierr = ISGetSize(subvertexIS, &numSubVerticesInitial);CHKERRQ(ierr);
10288   ierr = ISGetIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10289   for (v = 0; v < numSubVerticesInitial; ++v) {
10290     const PetscInt vertex = subVertices[v];
10291     PetscInt *star = PETSC_NULL;
10292     PetscInt  starSize, s, numFaces = 0, f;
10293 
10294     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10295     for (s = 0; s < starSize*2; s += 2) {
10296       const PetscInt point = star[s];
10297       if ((point >= fStart) && (point < fEnd)) {
10298         star[numFaces++] = point;
10299       }
10300     }
10301     for (f = 0; f < numFaces; ++f) {
10302       const PetscInt face    = star[f];
10303       PetscInt      *closure = PETSC_NULL;
10304       PetscInt       closureSize, c, numCorners = 0;
10305       PetscInt       faceLoc, corner;
10306 
10307       ierr = DMLabelGetValue(slabel, face, &faceLoc);CHKERRQ(ierr);
10308       if (faceLoc == dim-1) continue;
10309       if (faceLoc >= 0) SETERRQ2(comm, PETSC_ERR_PLIB, "Face %d has dimension %d in the surface label", face, faceLoc);
10310       ierr = DMPlexGetTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10311       for (c = 0; c < closureSize*2; c += 2) {
10312         const PetscInt point = closure[c];
10313         if ((point >= vStart) && (point < vEnd)) {
10314           closure[numCorners++] = point;
10315         }
10316       }
10317       for (corner = 0; corner < numCorners; ++corner) {
10318         const PetscInt cellVertex = closure[corner];
10319         PetscInt       vertexLoc;
10320 
10321         ierr = DMLabelGetValue(slabel, cellVertex, &vertexLoc);CHKERRQ(ierr);
10322         if (vertexLoc < 0) break;
10323       }
10324       ierr = DMPlexRestoreTransitiveClosure(dm, face, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10325       if (corner == numCorners) {
10326         const PetscInt *support;
10327         PetscInt        supportSize;
10328 
10329         for (corner = 0; corner < numCorners; ++corner) {ierr = DMLabelSetValue(slabel, closure[corner], 0);CHKERRQ(ierr);}
10330         ierr = DMLabelSetValue(slabel, face, dim-1);CHKERRQ(ierr);
10331         ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10332         ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10333         for(s = 0; s < supportSize; ++s) {
10334           ierr = DMLabelSetValue(slabel, support[s], dim);CHKERRQ(ierr);
10335         }
10336         if (dim > 2) {
10337           const PetscInt *cone;
10338           PetscInt        coneSize;
10339 
10340           ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10341           ierr = DMPlexGetCone(dm, face, &cone);CHKERRQ(ierr);
10342           for(c = 0; c < coneSize; ++c) {
10343             ierr = DMLabelSetValue(slabel, cone[c], dim-2);CHKERRQ(ierr);
10344           }
10345         }
10346       }
10347     }
10348     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10349   }
10350   ierr = ISRestoreIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10351   ierr = ISDestroy(&subvertexIS);CHKERRQ(ierr);
10352   ierr = DMLabelGetStratumSize(slabel, dim,   &numSubCells);CHKERRQ(ierr);
10353   ierr = DMLabelGetStratumSize(slabel, 0,     &numSubVertices);CHKERRQ(ierr);
10354   if (dim > 1) {ierr = DMLabelGetStratumSize(slabel, dim-1, &numSubFaces);CHKERRQ(ierr);}
10355   if (dim > 2) {ierr = DMLabelGetStratumSize(slabel, 1,     &numSubEdges);CHKERRQ(ierr);}
10356   ierr = DMPlexSetChart(subdm, 0, numSubCells+numSubFaces+numSubEdges+numSubVertices);CHKERRQ(ierr);
10357   ierr = DMPlexSetVTKCellHeight(subdm, 1);CHKERRQ(ierr);
10358   /* Set cone sizes */
10359   firstSubVertex = numSubCells;
10360   firstSubFace   = firstSubVertex + numSubVertices;
10361   firstSubEdge   = firstSubFace   + numSubFaces;
10362   ierr = DMLabelGetStratumIS(slabel, dim,   &subcellIS);CHKERRQ(ierr);
10363   ierr = ISGetIndices(subcellIS, &subCells);CHKERRQ(ierr);
10364   ierr = DMLabelGetStratumIS(slabel, 0,     &subvertexIS);CHKERRQ(ierr);
10365   ierr = ISGetIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10366   if (dim > 1) {
10367     ierr = DMLabelGetStratumIS(slabel, dim-1, &subfaceIS);CHKERRQ(ierr);
10368     ierr = ISGetIndices(subfaceIS, &subFaces);CHKERRQ(ierr);
10369   }
10370   if (dim > 2) {
10371     ierr = DMLabelGetStratumIS(slabel, 1,     &subedgeIS);CHKERRQ(ierr);
10372     ierr = ISGetIndices(subedgeIS, &subEdges);CHKERRQ(ierr);
10373   }
10374   for (e = firstSubEdge; e < firstSubEdge+numSubEdges; ++e) {
10375     ierr = DMPlexSetConeSize(subdm, e, 2);CHKERRQ(ierr);
10376   }
10377   for (f = 0; f < numSubFaces; ++f) {
10378     const PetscInt  face    = subFaces[f];
10379     const PetscInt  subface = firstSubFace + f;
10380     const PetscInt *support;
10381     PetscInt        coneSize, supportSize, subcell, s;
10382 
10383     ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10384     ierr = DMPlexSetConeSize(subdm, subface, coneSize);CHKERRQ(ierr);
10385     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10386     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10387     for(s = 0; s < supportSize; ++s) {
10388       ierr = PetscFindInt(support[s], numSubCells, subCells, &subcell);CHKERRQ(ierr);
10389       if (subcell < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Subcell %d not found in surface label", support[s]);
10390       /* ierr = DMPlexAddConeSize(subdm, subcell, 1);CHKERRQ(ierr); */
10391     }
10392   }
10393   ierr = DMSetUp(subdm);CHKERRQ(ierr);
10394   /* Set cones */
10395   for (e = 0; e < numSubEdges; ++e) {
10396     const PetscInt  edge    = subEdges[e];
10397     const PetscInt  subedge = firstSubEdge + e;
10398     const PetscInt *cone;
10399     PetscInt        coneSize, c, coneNew[2], subv;
10400 
10401     ierr = DMPlexGetConeSize(subdm, e, &coneSize);CHKERRQ(ierr);
10402     if (coneSize != 2) SETERRQ3(comm, PETSC_ERR_ARG_OUTOFRANGE, "Edge %d matching subedge %d had cone size %d != 2", edge, subedge, coneSize);
10403     ierr = DMPlexGetCone(subdm, e, &cone);CHKERRQ(ierr);
10404     for(c = 0; c < coneSize; ++c) {
10405       ierr = PetscFindInt(cone[c], numSubVertices, subVertices, &subv);CHKERRQ(ierr);
10406       if (subv < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Vertex %d has no matching subvertex", cone[v]);
10407       coneNew[c] = firstSubVertex + subv;
10408     }
10409     ierr = DMPlexSetCone(subdm, e, coneNew);CHKERRQ(ierr);
10410   }
10411   for (f = 0; f < numSubFaces; ++f) {
10412     const PetscInt  face    = subFaces[f];
10413     const PetscInt  subface = firstSubFace + f;
10414     const PetscInt *cone, *support;
10415     PetscInt        coneSize, supportSize, subvertex, subcell, c, s;
10416 
10417     ierr = DMPlexGetConeSize(dm, face, &coneSize);CHKERRQ(ierr);
10418     ierr = DMPlexGetCone(dm, face, &cone);CHKERRQ(ierr);
10419     for(c = 0; c < coneSize; ++c) {
10420       ierr = PetscFindInt(cone[c], numSubVertices, subVertices, &subvertex);CHKERRQ(ierr);
10421       if (subvertex < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Vertex %d has no matching subvertex", cone[v]);
10422       coneNew[c] = firstSubVertex + subvertex;
10423     }
10424     ierr = DMPlexSetCone(subdm, subface, coneNew);CHKERRQ(ierr);
10425     ierr = DMPlexGetSupportSize(dm, face, &supportSize);CHKERRQ(ierr);
10426     ierr = DMPlexGetSupport(dm, face, &support);CHKERRQ(ierr);
10427     for(s = 0; s < supportSize; ++s) {
10428       ierr = PetscFindInt(support[s], numSubCells, subCells, &subcell);CHKERRQ(ierr);
10429       if (subcell < 0) SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Subcell %d not found in surface label", support[s]);
10430       /* ierr = DMPlexAddCone(subdm, subcell, 1);CHKERRQ(ierr); */
10431     }
10432   }
10433   ierr = ISRestoreIndices(subcellIS, &subCells);CHKERRQ(ierr);
10434   ierr = ISDestroy(&subcellIS);CHKERRQ(ierr);
10435   ierr = ISRestoreIndices(subvertexIS, &subVertices);CHKERRQ(ierr);
10436   ierr = ISDestroy(&subvertexIS);CHKERRQ(ierr);
10437   if (dim > 1) {
10438     ierr = ISRestoreIndices(subfaceIS, &subFaces);CHKERRQ(ierr);
10439     ierr = ISDestroy(&subfaceIS);CHKERRQ(ierr);
10440   }
10441   if (dim > 2) {
10442     ierr = ISRestoreIndices(subedgeIS, &subEdges);CHKERRQ(ierr);
10443     ierr = ISDestroy(&subedgeIS);CHKERRQ(ierr);
10444   }
10445   ierr = DMPlexSymmetrize(subdm);CHKERRQ(ierr);
10446   ierr = DMPlexStratify(subdm);CHKERRQ(ierr);
10447   /* Build coordinates */
10448   {
10449     PetscSection    coordSection, subCoordSection;
10450     Vec             coordinates, subCoordinates;
10451     PetscScalar    *coords, *subCoords;
10452     PetscInt        coordSize;
10453 
10454     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10455     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10456     ierr = DMPlexGetCoordinateSection(subdm, &subCoordSection);CHKERRQ(ierr);
10457     ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVertices);CHKERRQ(ierr);
10458     for (v = 0; v < numSubVertices; ++v) {
10459       const PetscInt vertex    = subVertices[v];
10460       const PetscInt subVertex = firstSubVertex+v;
10461       PetscInt       dof;
10462 
10463       ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10464       ierr = PetscSectionSetDof(subCoordSection, subVertex, dof);CHKERRQ(ierr);
10465     }
10466     ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10467     ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10468     ierr = VecCreate(comm, &subCoordinates);CHKERRQ(ierr);
10469     ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10470     ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10471     ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10472     ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10473     for (v = 0; v < numSubVertices; ++v) {
10474       const PetscInt vertex    = subVertices[v];
10475       const PetscInt subVertex = firstSubVertex+v;
10476       PetscInt dof, off, sdof, soff, d;
10477 
10478       ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10479       ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10480       ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10481       ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10482       if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10483       for (d = 0; d < dof; ++d) {
10484         subCoords[soff+d] = coords[off+d];
10485       }
10486     }
10487     ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10488     ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10489     ierr = DMSetCoordinatesLocal(subdm, subCoordinates);CHKERRQ(ierr);
10490     ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10491   }
10492   /* TODO: Create map from submesh points to original mesh points */
10493   ierr = DMPlexSetSubpointMap(subdm, subpointMap);CHKERRQ(ierr);
10494   PetscFunctionReturn(0);
10495 }
10496 
10497 #undef __FUNCT__
10498 #define __FUNCT__ "DMPlexCreateSubmesh"
10499 /*
10500   DMPlexCreateSubmesh - Extract a hypersurface from the mesh using vertices defined by a label
10501 
10502   Input Parameters:
10503 + dm           - The original mesh
10504 . vertexLabel  - The DMLabel marking vertices contained in the surface
10505 - surfaceLabel - If not PETSC_NULL, create a new label with all the surface points labeled by dimension
10506 
10507   Output Parameter:
10508 . subdm - The surface mesh
10509 
10510   Level: developer
10511 
10512 .seealso: DMPlexGetLabel(), DMLabelSetValue()
10513 */
10514 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char vertexLabel[], const char surfaceLabel[], DM *subdm)
10515 {
10516   PetscInt       dim, depth;
10517   PetscErrorCode ierr;
10518 
10519   PetscFunctionBegin;
10520   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10521   PetscValidCharPointer(vertexLabel, 2);
10522   PetscValidPointer(subdm, 4);
10523   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10524   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
10525   ierr = DMCreate(((PetscObject) dm)->comm, subdm);CHKERRQ(ierr);
10526   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10527   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10528   if (depth == dim) {
10529     ierr = DMPlexCreateSubmesh_Interpolated(dm, vertexLabel, surfaceLabel, *subdm);CHKERRQ(ierr);
10530   } else {
10531     ierr = DMPlexCreateSubmesh_Uninterpolated(dm, vertexLabel, surfaceLabel, *subdm);CHKERRQ(ierr);
10532   }
10533   PetscFunctionReturn(0);
10534 }
10535 
10536 #undef __FUNCT__
10537 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10538 /* We can easily have a form that takes an IS instead */
10539 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10540 {
10541   PetscSection   section, globalSection;
10542   PetscInt       *numbers, p;
10543   PetscErrorCode ierr;
10544 
10545   PetscFunctionBegin;
10546   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10547   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10548   for (p = pStart; p < pEnd; ++p) {
10549     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10550   }
10551   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10552   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10553   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10554   for (p = pStart; p < pEnd; ++p) {
10555     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10556   }
10557   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10558   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10559   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10560   PetscFunctionReturn(0);
10561 }
10562 
10563 #undef __FUNCT__
10564 #define __FUNCT__ "DMPlexGetCellNumbering"
10565 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10566 {
10567   DM_Plex        *mesh = (DM_Plex*) dm->data;
10568   PetscInt       cellHeight, cStart, cEnd, cMax;
10569   PetscErrorCode ierr;
10570 
10571   PetscFunctionBegin;
10572   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10573   if (!mesh->globalCellNumbers) {
10574     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10575     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10576     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10577     if (cMax >= 0) cEnd = PetscMin(cEnd, cMax);
10578     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10579   }
10580   *globalCellNumbers = mesh->globalCellNumbers;
10581   PetscFunctionReturn(0);
10582 }
10583 
10584 #undef __FUNCT__
10585 #define __FUNCT__ "DMPlexGetVertexNumbering"
10586 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10587 {
10588   DM_Plex        *mesh = (DM_Plex*) dm->data;
10589   PetscInt       vStart, vEnd, vMax;
10590   PetscErrorCode ierr;
10591 
10592   PetscFunctionBegin;
10593   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10594   if (!mesh->globalVertexNumbers) {
10595     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10596     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10597     if (vMax >= 0) vEnd = PetscMin(vEnd, vMax);
10598     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10599   }
10600   *globalVertexNumbers = mesh->globalVertexNumbers;
10601   PetscFunctionReturn(0);
10602 }
10603 
10604 #undef __FUNCT__
10605 #define __FUNCT__ "DMPlexGetSubpointMap"
10606 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10607 {
10608   DM_Plex *mesh = (DM_Plex*) dm->data;
10609 
10610   PetscFunctionBegin;
10611   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10612   PetscValidPointer(subpointMap, 2);
10613   *subpointMap = mesh->subpointMap;
10614   PetscFunctionReturn(0);
10615 }
10616 
10617 #undef __FUNCT__
10618 #define __FUNCT__ "DMPlexSetSubpointMap"
10619 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10620 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10621 {
10622   DM_Plex       *mesh = (DM_Plex *) dm->data;
10623   PetscErrorCode ierr;
10624 
10625   PetscFunctionBegin;
10626   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10627   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10628   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
10629   mesh->subpointMap = subpointMap;
10630   ierr = PetscObjectReference((PetscObject) mesh->subpointMap);CHKERRQ(ierr);
10631   PetscFunctionReturn(0);
10632 }
10633 
10634 #undef __FUNCT__
10635 #define __FUNCT__ "DMPlexGetScale"
10636 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10637 {
10638   DM_Plex *mesh = (DM_Plex*) dm->data;
10639 
10640   PetscFunctionBegin;
10641   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10642   PetscValidPointer(scale, 3);
10643   *scale = mesh->scale[unit];
10644   PetscFunctionReturn(0);
10645 }
10646 
10647 #undef __FUNCT__
10648 #define __FUNCT__ "DMPlexSetScale"
10649 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10650 {
10651   DM_Plex *mesh = (DM_Plex*) dm->data;
10652 
10653   PetscFunctionBegin;
10654   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10655   mesh->scale[unit] = scale;
10656   PetscFunctionReturn(0);
10657 }
10658 
10659 
10660 /*******************************************************************************
10661 This should be in a separate Discretization object, but I am not sure how to lay
10662 it out yet, so I am stuffing things here while I experiment.
10663 *******************************************************************************/
10664 #undef __FUNCT__
10665 #define __FUNCT__ "DMPlexSetFEMIntegration"
10666 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10667                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10668                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10669                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10670                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10671                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10672                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10673                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10674                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10675                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10676                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10677                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10678                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10679                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10680                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10681                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10682                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10683 {
10684   DM_Plex *mesh = (DM_Plex*) dm->data;
10685 
10686   PetscFunctionBegin;
10687   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10688   mesh->integrateResidualFEM       = integrateResidualFEM;
10689   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10690   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10691   PetscFunctionReturn(0);
10692 }
10693 
10694 #undef __FUNCT__
10695 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10696 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10697 {
10698   Vec            coordinates;
10699   PetscSection   section, cSection;
10700   PetscInt       dim, vStart, vEnd, v, c, d;
10701   PetscScalar    *values, *cArray;
10702   PetscReal      *coords;
10703   PetscErrorCode ierr;
10704 
10705   PetscFunctionBegin;
10706   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10707   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10708   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10709   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10710   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10711   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10712   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10713   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10714   for (v = vStart; v < vEnd; ++v) {
10715     PetscInt dof, off;
10716 
10717     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10718     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10719     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10720     for (d = 0; d < dof; ++d) coords[d] = PetscRealPart(cArray[off+d]);
10721     for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10722     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10723   }
10724   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10725   /* Temporary, must be replaced by a projection on the finite element basis */
10726   {
10727     PetscInt eStart = 0, eEnd = 0, e, depth;
10728 
10729     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10730     --depth;
10731     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10732     for (e = eStart; e < eEnd; ++e) {
10733       const PetscInt *cone = PETSC_NULL;
10734       PetscInt       coneSize, d;
10735       PetscScalar    *coordsA, *coordsB;
10736 
10737       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10738       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10739       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10740       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10741       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10742       for (d = 0; d < dim; ++d) {
10743         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10744       }
10745       for (c = 0; c < numComp; ++c) values[c] = (*funcs[c])(coords);
10746       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10747     }
10748   }
10749 
10750   ierr = PetscFree(coords);CHKERRQ(ierr);
10751   ierr = PetscFree(values);CHKERRQ(ierr);
10752 #if 0
10753   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10754   PetscReal      detJ;
10755 
10756   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10757   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10758   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10759 
10760   for (PetscInt c = cStart; c < cEnd; ++c) {
10761     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10762     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10763     const int                         oSize    = pV.getSize();
10764     int                               v        = 0;
10765 
10766     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10767     for (PetscInt cl = 0; cl < oSize; ++cl) {
10768       const PetscInt fDim;
10769 
10770       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10771       if (pointDim) {
10772         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10773           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10774         }
10775       }
10776     }
10777     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10778     pV.clear();
10779   }
10780   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10781   ierr = PetscFree(values);CHKERRQ(ierr);
10782 #endif
10783   PetscFunctionReturn(0);
10784 }
10785 
10786 #undef __FUNCT__
10787 #define __FUNCT__ "DMPlexProjectFunction"
10788 /*@C
10789   DMPlexProjectFunction - This projects the given function into the function space provided.
10790 
10791   Input Parameters:
10792 + dm      - The DM
10793 . numComp - The number of components (functions)
10794 . funcs   - The coordinate functions to evaluate
10795 - mode    - The insertion mode for values
10796 
10797   Output Parameter:
10798 . X - vector
10799 
10800   Level: developer
10801 
10802   Note:
10803   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10804   We will eventually fix it.
10805 
10806 ,seealso: DMPlexComputeL2Diff()
10807 */
10808 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10809 {
10810   Vec            localX;
10811   PetscErrorCode ierr;
10812 
10813   PetscFunctionBegin;
10814   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10815   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10816   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10817   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10818   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10819   PetscFunctionReturn(0);
10820 }
10821 
10822 #undef __FUNCT__
10823 #define __FUNCT__ "DMPlexComputeL2Diff"
10824 /*@C
10825   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10826 
10827   Input Parameters:
10828 + dm    - The DM
10829 . quad  - The PetscQuadrature object for each field
10830 . funcs - The functions to evaluate for each field component
10831 - X     - The coefficient vector u_h
10832 
10833   Output Parameter:
10834 . diff - The diff ||u - u_h||_2
10835 
10836   Level: developer
10837 
10838 .seealso: DMPlexProjectFunction()
10839 */
10840 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10841 {
10842   const PetscInt debug = 0;
10843   PetscSection   section;
10844   Vec            localX;
10845   PetscReal      *coords, *v0, *J, *invJ, detJ;
10846   PetscReal      localDiff = 0.0;
10847   PetscInt       dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10848   PetscErrorCode ierr;
10849 
10850   PetscFunctionBegin;
10851   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10852   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10853   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10854   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10855   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10856   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10857   for (field = 0; field < numFields; ++field) {
10858     numComponents += quad[field].numComponents;
10859   }
10860   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10861   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10862   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10863   for (c = cStart; c < cEnd; ++c) {
10864     const PetscScalar *x;
10865     PetscReal         elemDiff = 0.0;
10866 
10867     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10868     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10869     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10870 
10871     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10872       const PetscInt  numQuadPoints = quad[field].numQuadPoints;
10873       const PetscReal *quadPoints   = quad[field].quadPoints;
10874       const PetscReal *quadWeights  = quad[field].quadWeights;
10875       const PetscInt  numBasisFuncs = quad[field].numBasisFuncs;
10876       const PetscInt  numBasisComps = quad[field].numComponents;
10877       const PetscReal *basis        = quad[field].basis;
10878       PetscInt        q, d, e, fc, f;
10879 
10880       if (debug) {
10881         char title[1024];
10882         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10883         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10884       }
10885       for (q = 0; q < numQuadPoints; ++q) {
10886         for (d = 0; d < dim; d++) {
10887           coords[d] = v0[d];
10888           for (e = 0; e < dim; e++) {
10889             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10890           }
10891         }
10892         for (fc = 0; fc < numBasisComps; ++fc) {
10893           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10894           PetscReal       interpolant = 0.0;
10895           for (f = 0; f < numBasisFuncs; ++f) {
10896             const PetscInt fidx = f*numBasisComps+fc;
10897             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10898           }
10899           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10900           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10901         }
10902       }
10903       comp        += numBasisComps;
10904       fieldOffset += numBasisFuncs*numBasisComps;
10905     }
10906     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10907     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10908     localDiff += elemDiff;
10909   }
10910   ierr  = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10911   ierr  = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10912   ierr  = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10913   *diff = PetscSqrtReal(*diff);
10914   PetscFunctionReturn(0);
10915 }
10916 
10917 #undef __FUNCT__
10918 #define __FUNCT__ "DMPlexComputeResidualFEM"
10919 /*@
10920   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10921 
10922   Input Parameters:
10923 + dm - The mesh
10924 . X  - Local input vector
10925 - user - The user context
10926 
10927   Output Parameter:
10928 . F  - Local output vector
10929 
10930   Note:
10931   The second member of the user context must be an FEMContext.
10932 
10933   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10934   like a GPU, or vectorize on a multicore machine.
10935 
10936 .seealso: DMPlexComputeJacobianActionFEM()
10937 */
10938 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10939 {
10940   DM_Plex         *mesh = (DM_Plex*) dm->data;
10941   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
10942   PetscQuadrature *quad = fem->quad;
10943   PetscSection    section;
10944   PetscReal       *v0, *J, *invJ, *detJ;
10945   PetscScalar     *elemVec, *u;
10946   PetscInt        dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10947   PetscInt        cellDof = 0, numComponents = 0;
10948   PetscErrorCode  ierr;
10949 
10950   PetscFunctionBegin;
10951   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10952   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10953   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10954   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10955   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10956   numCells = cEnd - cStart;
10957   for (field = 0; field < numFields; ++field) {
10958     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
10959     numComponents += quad[field].numComponents;
10960   }
10961   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10962   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10963   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
10964   for (c = cStart; c < cEnd; ++c) {
10965     const PetscScalar *x;
10966     PetscInt          i;
10967 
10968     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10969     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10970     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10971 
10972     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
10973     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10974   }
10975   for (field = 0; field < numFields; ++field) {
10976     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10977     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10978     void           (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10979     void           (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10980     /* Conforming batches */
10981     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10982     PetscInt numBlocks  = 1;
10983     PetscInt batchSize  = numBlocks * blockSize;
10984     PetscInt numBatches = numBatchesTmp;
10985     PetscInt numChunks  = numCells / (numBatches*batchSize);
10986     /* Remainder */
10987     PetscInt numRemainder = numCells % (numBatches * batchSize);
10988     PetscInt offset       = numCells - numRemainder;
10989 
10990     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10991     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10992                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10993   }
10994   for (c = cStart; c < cEnd; ++c) {
10995     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10996     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10997   }
10998   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10999   if (mesh->printFEM) {
11000     PetscMPIInt rank, numProcs;
11001     PetscInt    p;
11002 
11003     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
11004     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
11005     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
11006     for (p = 0; p < numProcs; ++p) {
11007       if (p == rank) {
11008         Vec f;
11009 
11010         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
11011         ierr = VecCopy(F, f);CHKERRQ(ierr);
11012         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
11013         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
11014         ierr = VecDestroy(&f);CHKERRQ(ierr);
11015         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
11016       }
11017       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
11018     }
11019   }
11020   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11021   PetscFunctionReturn(0);
11022 }
11023 
11024 #undef __FUNCT__
11025 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
11026 /*@C
11027   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
11028 
11029   Input Parameters:
11030 + dm - The mesh
11031 . J  - The Jacobian shell matrix
11032 . X  - Local input vector
11033 - user - The user context
11034 
11035   Output Parameter:
11036 . F  - Local output vector
11037 
11038   Note:
11039   The second member of the user context must be an FEMContext.
11040 
11041   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
11042   like a GPU, or vectorize on a multicore machine.
11043 
11044 .seealso: DMPlexComputeResidualFEM()
11045 */
11046 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
11047 {
11048   DM_Plex         *mesh = (DM_Plex*) dm->data;
11049   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
11050   PetscQuadrature *quad = fem->quad;
11051   PetscSection    section;
11052   JacActionCtx    *jctx;
11053   PetscReal       *v0, *J, *invJ, *detJ;
11054   PetscScalar     *elemVec, *u, *a;
11055   PetscInt        dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
11056   PetscInt        cellDof = 0;
11057   PetscErrorCode  ierr;
11058 
11059   PetscFunctionBegin;
11060   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11061   ierr     = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
11062   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
11063   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
11064   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
11065   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
11066   numCells = cEnd - cStart;
11067   for (field = 0; field < numFields; ++field) {
11068     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
11069   }
11070   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
11071   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);
11072   for (c = cStart; c < cEnd; ++c) {
11073     const PetscScalar *x;
11074     PetscInt          i;
11075 
11076     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
11077     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
11078     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
11079     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
11080     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
11081     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
11082     for (i = 0; i < cellDof; ++i) a[c*cellDof+i] = x[i];
11083     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
11084   }
11085   for (field = 0; field < numFields; ++field) {
11086     const PetscInt numQuadPoints = quad[field].numQuadPoints;
11087     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
11088     /* Conforming batches */
11089     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
11090     PetscInt numBlocks  = 1;
11091     PetscInt batchSize  = numBlocks * blockSize;
11092     PetscInt numBatches = numBatchesTmp;
11093     PetscInt numChunks  = numCells / (numBatches*batchSize);
11094     /* Remainder */
11095     PetscInt numRemainder = numCells % (numBatches * batchSize);
11096     PetscInt offset       = numCells - numRemainder;
11097 
11098     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);
11099     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],
11100                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
11101   }
11102   for (c = cStart; c < cEnd; ++c) {
11103     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
11104     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
11105   }
11106   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
11107   if (mesh->printFEM) {
11108     PetscMPIInt rank, numProcs;
11109     PetscInt    p;
11110 
11111     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
11112     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
11113     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
11114     for (p = 0; p < numProcs; ++p) {
11115       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
11116       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
11117     }
11118   }
11119   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11120   PetscFunctionReturn(0);
11121 }
11122 
11123 #undef __FUNCT__
11124 #define __FUNCT__ "DMPlexComputeJacobianFEM"
11125 /*@
11126   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
11127 
11128   Input Parameters:
11129 + dm - The mesh
11130 . X  - Local input vector
11131 - user - The user context
11132 
11133   Output Parameter:
11134 . Jac  - Jacobian matrix
11135 
11136   Note:
11137   The second member of the user context must be an FEMContext.
11138 
11139   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
11140   like a GPU, or vectorize on a multicore machine.
11141 
11142 .seealso: FormFunctionLocal()
11143 */
11144 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
11145 {
11146   DM_Plex         *mesh = (DM_Plex*) dm->data;
11147   PetscFEM        *fem  = (PetscFEM*) &((DM*) user)[1];
11148   PetscQuadrature *quad = fem->quad;
11149   PetscSection    section;
11150   PetscReal       *v0, *J, *invJ, *detJ;
11151   PetscScalar     *elemMat, *u;
11152   PetscInt        dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
11153   PetscInt        cellDof = 0, numComponents = 0;
11154   PetscBool       isShell;
11155   PetscErrorCode  ierr;
11156 
11157   PetscFunctionBegin;
11158   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11159   ierr     = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
11160   ierr     = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
11161   ierr     = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
11162   ierr     = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
11163   numCells = cEnd - cStart;
11164   for (field = 0; field < numFields; ++field) {
11165     cellDof       += quad[field].numBasisFuncs*quad[field].numComponents;
11166     numComponents += quad[field].numComponents;
11167   }
11168   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
11169   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
11170   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);
11171   for (c = cStart; c < cEnd; ++c) {
11172     const PetscScalar *x;
11173     PetscInt          i;
11174 
11175     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
11176     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
11177     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
11178 
11179     for (i = 0; i < cellDof; ++i) u[c*cellDof+i] = x[i];
11180     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
11181   }
11182   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
11183   for (fieldI = 0; fieldI < numFields; ++fieldI) {
11184     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
11185     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
11186     PetscInt       fieldJ;
11187 
11188     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
11189       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
11190       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
11191       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
11192       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
11193       /* Conforming batches */
11194       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
11195       PetscInt numBlocks  = 1;
11196       PetscInt batchSize  = numBlocks * blockSize;
11197       PetscInt numBatches = numBatchesTmp;
11198       PetscInt numChunks  = numCells / (numBatches*batchSize);
11199       /* Remainder */
11200       PetscInt numRemainder = numCells % (numBatches * batchSize);
11201       PetscInt offset       = numCells - numRemainder;
11202 
11203       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
11204       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
11205                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
11206     }
11207   }
11208   for (c = cStart; c < cEnd; ++c) {
11209     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
11210     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
11211   }
11212   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
11213 
11214   /* Assemble matrix, using the 2-step process:
11215        MatAssemblyBegin(), MatAssemblyEnd(). */
11216   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11217   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11218 
11219   if (mesh->printFEM) {
11220     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
11221     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
11222     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
11223   }
11224   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11225   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
11226   if (isShell) {
11227     JacActionCtx *jctx;
11228 
11229     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
11230     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
11231   }
11232   *str = SAME_NONZERO_PATTERN;
11233   PetscFunctionReturn(0);
11234 }
11235 
11236 
11237 #undef __FUNCT__
11238 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
11239 /*@C
11240   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
11241   the local section and an SF describing the section point overlap.
11242 
11243   Input Parameters:
11244   + s - The PetscSection for the local field layout
11245   . sf - The SF describing parallel layout of the section points
11246   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
11247   . label - The label specifying the points
11248   - labelValue - The label stratum specifying the points
11249 
11250   Output Parameter:
11251   . gsection - The PetscSection for the global field layout
11252 
11253   Note: This gives negative sizes and offsets to points not owned by this process
11254 
11255   Level: developer
11256 
11257 .seealso: PetscSectionCreate()
11258 @*/
11259 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
11260 {
11261   PetscInt       *neg;
11262   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
11263   PetscErrorCode ierr;
11264 
11265   PetscFunctionBegin;
11266   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
11267   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
11268   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
11269   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
11270   /* Mark ghost points with negative dof */
11271   for (p = pStart; p < pEnd; ++p) {
11272     PetscInt value;
11273 
11274     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11275     if (value != labelValue) continue;
11276     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11277     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11278     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11279     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11280     neg[p-pStart] = -(dof+1);
11281   }
11282   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11283   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11284   if (nroots >= 0) {
11285     if (nroots > pEnd - pStart) {
11286       PetscInt *tmpDof;
11287       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11288       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11289       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11290       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11291       for (p = pStart; p < pEnd; ++p) {
11292         if (tmpDof[p] < 0) (*gsection)->atlasDof[p-pStart] = tmpDof[p];
11293       }
11294       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11295     } else {
11296       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11297       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11298     }
11299   }
11300   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11301   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11302     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11303 
11304     (*gsection)->atlasOff[p] = off;
11305 
11306     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11307   }
11308   ierr       = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11309   globalOff -= off;
11310   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11311     (*gsection)->atlasOff[p] += globalOff;
11312 
11313     neg[p] = -((*gsection)->atlasOff[p]+1);
11314   }
11315   /* Put in negative offsets for ghost points */
11316   if (nroots >= 0) {
11317     if (nroots > pEnd - pStart) {
11318       PetscInt *tmpOff;
11319       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11320       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11321       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11322       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11323       for (p = pStart; p < pEnd; ++p) {
11324         if (tmpOff[p] < 0) (*gsection)->atlasOff[p-pStart] = tmpOff[p];
11325       }
11326       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11327     } else {
11328       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11329       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11330     }
11331   }
11332   ierr = PetscFree(neg);CHKERRQ(ierr);
11333   PetscFunctionReturn(0);
11334 }
11335