xref: /petsc/src/dm/impls/plex/plex.c (revision 5c8f6a953e7ed1c81f507d64aebddb11080b60e9)
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     if (markers) {
167       ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
168     }
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors = 3;
180     PetscReal    scale = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = PETSC_NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm = ((PetscObject) dm)->comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscMPIInt size;
282 
283     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
284     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
285     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
286     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
287     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
288     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
289     if (depth == 1) {
290       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
291       pEnd = pEnd - pStart;
292       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
293       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
294       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
295       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
296       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
297       pEnd = pEnd - pStart;
298       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
299       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
300       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
301       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
302     } else {
303       for (d = 0; d <= dim; d++) {
304         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
305         pEnd = pEnd - pStart;
306         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
307         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
308         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
309         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
310       }
311     }
312     ierr = PetscFree(sizes);CHKERRQ(ierr);
313   }
314   PetscFunctionReturn(0);
315 }
316 
317 #undef __FUNCT__
318 #define __FUNCT__ "DMView_Plex"
319 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
320 {
321   PetscBool      iascii, isbinary;
322   PetscErrorCode ierr;
323 
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
326   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
327   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
329   if (iascii) {
330     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
331 #if 0
332   } else if (isbinary) {
333     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
334 #endif
335   }
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "DMDestroy_Plex"
341 PetscErrorCode DMDestroy_Plex(DM dm)
342 {
343   DM_Plex    *mesh = (DM_Plex *) dm->data;
344   DMLabel        next = mesh->labels;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   if (--mesh->refct > 0) {PetscFunctionReturn(0);}
349   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
350   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
352   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
353   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
355   while (next) {
356     DMLabel tmp = next->next;
357 
358     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
359     next = tmp;
360   }
361   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
362   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
364   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
365   ierr = PetscFree(mesh);CHKERRQ(ierr);
366   PetscFunctionReturn(0);
367 }
368 
369 #undef __FUNCT__
370 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
371 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
372 {
373   const PetscInt *support = PETSC_NULL;
374   PetscInt        numAdj  = 0, maxAdjSize = *adjSize, supportSize, s;
375   PetscErrorCode  ierr;
376 
377   PetscFunctionBegin;
378   if (useClosure) {
379     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
380     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
381     for (s = 0; s < supportSize; ++s) {
382       const PetscInt *cone = PETSC_NULL;
383       PetscInt        coneSize, c, q;
384 
385       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
386       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
387       for (c = 0; c < coneSize; ++c) {
388         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
389           if (cone[c] == adj[q]) break;
390         }
391         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
392       }
393     }
394   } else {
395     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
396     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
397     for (s = 0; s < supportSize; ++s) {
398       const PetscInt *cone = PETSC_NULL;
399       PetscInt        coneSize, c, q;
400 
401       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
402       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
403       for (c = 0; c < coneSize; ++c) {
404         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
405           if (cone[c] == adj[q]) break;
406         }
407         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
408       }
409     }
410   }
411   *adjSize = numAdj;
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "DMPlexGetAdjacency_Private"
417 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
418 {
419   const PetscInt *star   = tmpClosure;
420   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
421   PetscErrorCode  ierr;
422 
423   PetscFunctionBegin;
424   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt **) &star);CHKERRQ(ierr);
425   for (s = 2; s < starSize*2; s += 2) {
426     const PetscInt *closure = PETSC_NULL;
427     PetscInt        closureSize, c, q;
428 
429     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
430     for (c = 0; c < closureSize*2; c += 2) {
431       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
432         if (closure[c] == adj[q]) break;
433       }
434       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
435     }
436     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
437   }
438   *adjSize = numAdj;
439   PetscFunctionReturn(0);
440 }
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
444 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
445 {
446   DM_Plex *mesh = (DM_Plex *) dm->data;
447 
448   PetscFunctionBegin;
449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
450   mesh->preallocCenterDim = preallocCenterDim;
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "DMPlexPreallocateOperator"
456 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
457 {
458   DM_Plex        *mesh = (DM_Plex *) dm->data;
459   MPI_Comm           comm = ((PetscObject) dm)->comm;
460   PetscSF            sf, sfDof, sfAdj;
461   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
462   PetscInt           nleaves, l, p;
463   const PetscInt    *leaves;
464   const PetscSFNode *remotes;
465   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
466   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
467   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
468   PetscLayout        rLayout;
469   PetscInt           locRows, rStart, rEnd, r;
470   PetscMPIInt        size;
471   PetscBool          useClosure, debug = PETSC_FALSE;
472   PetscErrorCode     ierr;
473 
474   PetscFunctionBegin;
475   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
476   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
477   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
478   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
479   /* Create dof SF based on point SF */
480   if (debug) {
481     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
487   }
488   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
489   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
490   if (debug) {
491     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
492     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
493   }
494   /* Create section for dof adjacency (dof ==> # adj dof) */
495   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
496   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
497   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
498   if (mesh->preallocCenterDim == dim) {
499     useClosure = PETSC_FALSE;
500   } else if (mesh->preallocCenterDim == 0) {
501     useClosure = PETSC_TRUE;
502   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
503 
504   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
505   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
510   /*   Fill in the ghost dofs on the interface */
511   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
512   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
513   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
514   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
515   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
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) {
639     rootAdj[r] = -1;
640   }
641   if (size > 1) {
642     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
643     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
644   }
645   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
646   ierr = PetscFree(adj);CHKERRQ(ierr);
647   /* Debugging */
648   if (debug) {
649     IS tmp;
650     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
651     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
652     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
653   }
654   /* Add in local adjacency indices for owned dofs on interface (roots) */
655   for (p = pStart; p < pEnd; ++p) {
656     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
657 
658     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
659     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
660     if (!dof) continue;
661     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
662     if (adof <= 0) continue;
663     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
664     for (d = off; d < off+dof; ++d) {
665       PetscInt adof, aoff, i;
666 
667       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
668       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
669       i    = adof-1;
670       for (q = 0; q < numAdj; ++q) {
671         PetscInt ndof, ncdof, ngoff, nd;
672 
673         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
674         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
675         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
676         for (nd = 0; nd < ndof-ncdof; ++nd) {
677           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
678           --i;
679         }
680       }
681     }
682   }
683   /* Debugging */
684   if (debug) {
685     IS tmp;
686     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
687     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
688     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
689   }
690   /* Compress indices */
691   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
692   for (p = pStart; p < pEnd; ++p) {
693     PetscInt dof, cdof, off, d;
694     PetscInt adof, aoff;
695 
696     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
697     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
698     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
699     if (!dof) continue;
700     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
701     if (adof <= 0) continue;
702     for (d = off; d < off+dof-cdof; ++d) {
703       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
704       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
705       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
706       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
707     }
708   }
709   /* Debugging */
710   if (debug) {
711     IS tmp;
712     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
713     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
714     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
715     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
716     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
717   }
718   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
719   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
720   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
721   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
722   for (p = pStart; p < pEnd; ++p) {
723     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
724     PetscBool found  = PETSC_TRUE;
725 
726     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
727     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
728     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
729     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
730     for (d = 0; d < dof-cdof; ++d) {
731       PetscInt ldof, rdof;
732 
733       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
734       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
735       if (ldof > 0) {
736         /* We do not own this point */
737       } else if (rdof > 0) {
738         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
739       } else {
740         found = PETSC_FALSE;
741       }
742     }
743     if (found) continue;
744     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
745     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
746     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
747     for (q = 0; q < numAdj; ++q) {
748       PetscInt ndof, ncdof, noff;
749 
750       /* Adjacent points may not be in the section chart */
751       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
752       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
753       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
754       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
755       for (d = goff; d < goff+dof-cdof; ++d) {
756         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
757       }
758     }
759   }
760   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
761   if (debug) {
762     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
763     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
764   }
765   /* Get adjacent indices */
766   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
767   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
768   for (p = pStart; p < pEnd; ++p) {
769     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
770     PetscBool found  = PETSC_TRUE;
771 
772     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
773     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
774     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
775     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
776     for (d = 0; d < dof-cdof; ++d) {
777       PetscInt ldof, rdof;
778 
779       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
780       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
781       if (ldof > 0) {
782         /* We do not own this point */
783       } else if (rdof > 0) {
784         PetscInt aoff, roff;
785 
786         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
787         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
788         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
789       } else {
790         found = PETSC_FALSE;
791       }
792     }
793     if (found) continue;
794     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
795     for (d = goff; d < goff+dof-cdof; ++d) {
796       PetscInt adof, aoff, i = 0;
797 
798       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
799       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
800       for (q = 0; q < numAdj; ++q) {
801         PetscInt        ndof, ncdof, ngoff, nd;
802         const PetscInt *ncind;
803 
804         /* Adjacent points may not be in the section chart */
805         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
806         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
807         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
808         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
809         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
810         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
811           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
812         }
813       }
814       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);
815     }
816   }
817   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
818   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
819   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
820   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
821   /* Debugging */
822   if (debug) {
823     IS tmp;
824     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
825     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
826     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
827   }
828   /* Create allocation vectors from adjacency graph */
829   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
830   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
831   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
832   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
833   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
834   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
835   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
836   /* Only loop over blocks of rows */
837   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);
838   for (r = rStart/bs; r < rEnd/bs; ++r) {
839     const PetscInt row = r*bs;
840     PetscInt numCols, cStart, c;
841 
842     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
843     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
844     for (c = cStart; c < cStart+numCols; ++c) {
845       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
846         ++dnz[r-rStart];
847         if (cols[c] >= row) {++dnzu[r-rStart];}
848       } else {
849         ++onz[r-rStart];
850         if (cols[c] >= row) {++onzu[r-rStart];}
851       }
852     }
853   }
854   if (bs > 1) {
855     for (r = 0; r < locRows/bs; ++r) {
856       dnz[r]  /= bs;
857       onz[r]  /= bs;
858       dnzu[r] /= bs;
859       onzu[r] /= bs;
860     }
861   }
862   /* Set matrix pattern */
863   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
864   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
865   /* Fill matrix with zeros */
866   if (fillMatrix) {
867     PetscScalar *values;
868     PetscInt     maxRowLen = 0;
869 
870     for (r = rStart; r < rEnd; ++r) {
871       PetscInt len;
872 
873       ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
874       maxRowLen = PetscMax(maxRowLen, len);
875     }
876     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
877     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
878     for (r = rStart; r < rEnd; ++r) {
879       PetscInt numCols, cStart;
880 
881       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
882       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
883       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
884     }
885     ierr = PetscFree(values);CHKERRQ(ierr);
886     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
887     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
888   }
889   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
890   ierr = PetscFree(cols);CHKERRQ(ierr);
891   PetscFunctionReturn(0);
892 }
893 
894 #if 0
895 #undef __FUNCT__
896 #define __FUNCT__ "DMPlexPreallocateOperator_2"
897 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
898 {
899   PetscErrorCode ierr;
900   PetscInt c,cStart,cEnd,pStart,pEnd;
901   PetscInt *tmpClosure,*tmpAdj,*visits;
902 
903   PetscFunctionBegin;
904   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
905   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
906   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
907   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
908   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
911   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
912   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
914   for (c=cStart; c<cEnd; c++) {
915     PetscInt *support = tmpClosure;
916     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
917     for (p=0; p<supportSize; p++) {
918       lvisits[support[p]]++;
919     }
920   }
921   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
923   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
925 
926   ierr = PetscSFGetRanks();CHKERRQ(ierr);
927 
928 
929   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
930   for (c=cStart; c<cEnd; c++) {
931     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
932     /*
933      Depth-first walk of transitive closure.
934      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.
935      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
936      */
937   }
938 
939   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
940   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
941   PetscFunctionReturn(0);
942 }
943 #endif
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "DMCreateMatrix_Plex"
947 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
948 {
949   PetscSection   section, sectionGlobal;
950   PetscInt       bs = -1;
951   PetscInt       localSize;
952   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
953   PetscErrorCode ierr;
954 
955   PetscFunctionBegin;
956 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
957   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
958 #endif
959   if (!mtype) mtype = MATAIJ;
960   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
961   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
962   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
963   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
964   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
965   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
966   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
967   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
975   /* Check for symmetric storage */
976   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
977   if (isSymmetric) {
978     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
979   }
980   if (!isShell) {
981     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
982     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal;
983 
984     if (bs < 0) {
985       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
986         PetscInt pStart, pEnd, p, dof;
987 
988         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
989         for (p = pStart; p < pEnd; ++p) {
990           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
991           if (dof) {
992             bs = dof;
993             break;
994           }
995         }
996       } else {
997         bs = 1;
998       }
999       /* Must have same blocksize on all procs (some might have no points) */
1000       bsLocal = bs;
1001       ierr = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1002     }
1003     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1004     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1005     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1006     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1007     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1008     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1009     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1010   }
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 #undef __FUNCT__
1015 #define __FUNCT__ "DMPlexGetDimension"
1016 /*@
1017   DMPlexGetDimension - Return the topological mesh dimension
1018 
1019   Not collective
1020 
1021   Input Parameter:
1022 . mesh - The DMPlex
1023 
1024   Output Parameter:
1025 . dim - The topological mesh dimension
1026 
1027   Level: beginner
1028 
1029 .seealso: DMPlexCreate()
1030 @*/
1031 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1032 {
1033   DM_Plex *mesh = (DM_Plex *) dm->data;
1034 
1035   PetscFunctionBegin;
1036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1037   PetscValidPointer(dim, 2);
1038   *dim = mesh->dim;
1039   PetscFunctionReturn(0);
1040 }
1041 
1042 #undef __FUNCT__
1043 #define __FUNCT__ "DMPlexSetDimension"
1044 /*@
1045   DMPlexSetDimension - Set the topological mesh dimension
1046 
1047   Collective on mesh
1048 
1049   Input Parameters:
1050 + mesh - The DMPlex
1051 - dim - The topological mesh dimension
1052 
1053   Level: beginner
1054 
1055 .seealso: DMPlexCreate()
1056 @*/
1057 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1058 {
1059   DM_Plex *mesh = (DM_Plex *) dm->data;
1060 
1061   PetscFunctionBegin;
1062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1063   PetscValidLogicalCollectiveInt(dm, dim, 2);
1064   mesh->dim = dim;
1065   mesh->preallocCenterDim = dim;
1066   PetscFunctionReturn(0);
1067 }
1068 
1069 #undef __FUNCT__
1070 #define __FUNCT__ "DMPlexGetChart"
1071 /*@
1072   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1073 
1074   Not collective
1075 
1076   Input Parameter:
1077 . mesh - The DMPlex
1078 
1079   Output Parameters:
1080 + pStart - The first mesh point
1081 - pEnd   - The upper bound for mesh points
1082 
1083   Level: beginner
1084 
1085 .seealso: DMPlexCreate(), DMPlexSetChart()
1086 @*/
1087 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1088 {
1089   DM_Plex    *mesh = (DM_Plex *) dm->data;
1090   PetscErrorCode ierr;
1091 
1092   PetscFunctionBegin;
1093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1094   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1095   PetscFunctionReturn(0);
1096 }
1097 
1098 #undef __FUNCT__
1099 #define __FUNCT__ "DMPlexSetChart"
1100 /*@
1101   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1102 
1103   Not collective
1104 
1105   Input Parameters:
1106 + mesh - The DMPlex
1107 . pStart - The first mesh point
1108 - pEnd   - The upper bound for mesh points
1109 
1110   Output Parameters:
1111 
1112   Level: beginner
1113 
1114 .seealso: DMPlexCreate(), DMPlexGetChart()
1115 @*/
1116 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1117 {
1118   DM_Plex    *mesh = (DM_Plex *) dm->data;
1119   PetscErrorCode ierr;
1120 
1121   PetscFunctionBegin;
1122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1123   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1124   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 #undef __FUNCT__
1129 #define __FUNCT__ "DMPlexGetConeSize"
1130 /*@
1131   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1132 
1133   Not collective
1134 
1135   Input Parameters:
1136 + mesh - The DMPlex
1137 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1138 
1139   Output Parameter:
1140 . size - The cone size for point p
1141 
1142   Level: beginner
1143 
1144 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1145 @*/
1146 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1147 {
1148   DM_Plex    *mesh = (DM_Plex *) dm->data;
1149   PetscErrorCode ierr;
1150 
1151   PetscFunctionBegin;
1152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1153   PetscValidPointer(size, 3);
1154   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1155   PetscFunctionReturn(0);
1156 }
1157 
1158 #undef __FUNCT__
1159 #define __FUNCT__ "DMPlexSetConeSize"
1160 /*@
1161   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1162 
1163   Not collective
1164 
1165   Input Parameters:
1166 + mesh - The DMPlex
1167 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1168 - size - The cone size for point p
1169 
1170   Output Parameter:
1171 
1172   Note:
1173   This should be called after DMPlexSetChart().
1174 
1175   Level: beginner
1176 
1177 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1178 @*/
1179 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1180 {
1181   DM_Plex    *mesh = (DM_Plex *) dm->data;
1182   PetscErrorCode ierr;
1183 
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1186   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1187   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1188   PetscFunctionReturn(0);
1189 }
1190 
1191 #undef __FUNCT__
1192 #define __FUNCT__ "DMPlexGetCone"
1193 /*@C
1194   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1195 
1196   Not collective
1197 
1198   Input Parameters:
1199 + mesh - The DMPlex
1200 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1201 
1202   Output Parameter:
1203 . cone - An array of points which are on the in-edges for point p
1204 
1205   Level: beginner
1206 
1207   Note:
1208   This routine is not available in Fortran.
1209 
1210 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1211 @*/
1212 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1213 {
1214   DM_Plex    *mesh = (DM_Plex *) dm->data;
1215   PetscInt       off;
1216   PetscErrorCode ierr;
1217 
1218   PetscFunctionBegin;
1219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1220   PetscValidPointer(cone, 3);
1221   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1222   *cone = &mesh->cones[off];
1223   PetscFunctionReturn(0);
1224 }
1225 
1226 #undef __FUNCT__
1227 #define __FUNCT__ "DMPlexSetCone"
1228 /*@
1229   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1230 
1231   Not collective
1232 
1233   Input Parameters:
1234 + mesh - The DMPlex
1235 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1236 - cone - An array of points which are on the in-edges for point p
1237 
1238   Output Parameter:
1239 
1240   Note:
1241   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1242 
1243   Level: beginner
1244 
1245 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1246 @*/
1247 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1248 {
1249   DM_Plex    *mesh = (DM_Plex *) dm->data;
1250   PetscInt       pStart, pEnd;
1251   PetscInt       dof, off, c;
1252   PetscErrorCode ierr;
1253 
1254   PetscFunctionBegin;
1255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1256   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1257   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1258   if (dof) PetscValidPointer(cone, 3);
1259   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1260   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);
1261   for (c = 0; c < dof; ++c) {
1262     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);
1263     mesh->cones[off+c] = cone[c];
1264   }
1265   PetscFunctionReturn(0);
1266 }
1267 
1268 #undef __FUNCT__
1269 #define __FUNCT__ "DMPlexGetConeOrientation"
1270 /*@C
1271   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1272 
1273   Not collective
1274 
1275   Input Parameters:
1276 + mesh - The DMPlex
1277 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1278 
1279   Output Parameter:
1280 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1281                     integer giving the prescription for cone traversal. If it is negative, the cone is
1282                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1283                     the index of the cone point on which to start.
1284 
1285   Level: beginner
1286 
1287   Note:
1288   This routine is not available in Fortran.
1289 
1290 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1291 @*/
1292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1293 {
1294   DM_Plex    *mesh = (DM_Plex *) dm->data;
1295   PetscInt       off;
1296   PetscErrorCode ierr;
1297 
1298   PetscFunctionBegin;
1299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1300 #if defined(PETSC_USE_DEBUG)
1301   {
1302     PetscInt dof;
1303     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1304     if (dof) PetscValidPointer(coneOrientation, 3);
1305   }
1306 #endif
1307   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1308   *coneOrientation = &mesh->coneOrientations[off];
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 #undef __FUNCT__
1313 #define __FUNCT__ "DMPlexSetConeOrientation"
1314 /*@
1315   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1316 
1317   Not collective
1318 
1319   Input Parameters:
1320 + mesh - The DMPlex
1321 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1322 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1323                     integer giving the prescription for cone traversal. If it is negative, the cone is
1324                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1325                     the index of the cone point on which to start.
1326 
1327   Output Parameter:
1328 
1329   Note:
1330   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1331 
1332   Level: beginner
1333 
1334 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1335 @*/
1336 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1337 {
1338   DM_Plex    *mesh = (DM_Plex *) dm->data;
1339   PetscInt       pStart, pEnd;
1340   PetscInt       dof, off, c;
1341   PetscErrorCode ierr;
1342 
1343   PetscFunctionBegin;
1344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1345   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1346   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1347   if (dof) PetscValidPointer(coneOrientation, 3);
1348   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1349   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);
1350   for (c = 0; c < dof; ++c) {
1351     PetscInt cdof, o = coneOrientation[c];
1352 
1353     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1354     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);
1355     mesh->coneOrientations[off+c] = o;
1356   }
1357   PetscFunctionReturn(0);
1358 }
1359 
1360 #undef __FUNCT__
1361 #define __FUNCT__ "DMPlexInsertCone"
1362 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1363 {
1364   DM_Plex    *mesh = (DM_Plex *) dm->data;
1365   PetscInt       pStart, pEnd;
1366   PetscInt       dof, off;
1367   PetscErrorCode ierr;
1368 
1369   PetscFunctionBegin;
1370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1371   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1372   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1373   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1374   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);
1375   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);
1376   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);
1377   mesh->cones[off+conePos] = conePoint;
1378   PetscFunctionReturn(0);
1379 }
1380 
1381 #undef __FUNCT__
1382 #define __FUNCT__ "DMPlexGetSupportSize"
1383 /*@
1384   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1385 
1386   Not collective
1387 
1388   Input Parameters:
1389 + mesh - The DMPlex
1390 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1391 
1392   Output Parameter:
1393 . size - The support size for point p
1394 
1395   Level: beginner
1396 
1397 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1398 @*/
1399 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1400 {
1401   DM_Plex    *mesh = (DM_Plex *) dm->data;
1402   PetscErrorCode ierr;
1403 
1404   PetscFunctionBegin;
1405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1406   PetscValidPointer(size, 3);
1407   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1408   PetscFunctionReturn(0);
1409 }
1410 
1411 #undef __FUNCT__
1412 #define __FUNCT__ "DMPlexSetSupportSize"
1413 /*@
1414   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1415 
1416   Not collective
1417 
1418   Input Parameters:
1419 + mesh - The DMPlex
1420 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1421 - size - The support size for point p
1422 
1423   Output Parameter:
1424 
1425   Note:
1426   This should be called after DMPlexSetChart().
1427 
1428   Level: beginner
1429 
1430 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1431 @*/
1432 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1433 {
1434   DM_Plex    *mesh = (DM_Plex *) dm->data;
1435   PetscErrorCode ierr;
1436 
1437   PetscFunctionBegin;
1438   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1439   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1440   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1441   PetscFunctionReturn(0);
1442 }
1443 
1444 #undef __FUNCT__
1445 #define __FUNCT__ "DMPlexGetSupport"
1446 /*@C
1447   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1448 
1449   Not collective
1450 
1451   Input Parameters:
1452 + mesh - The DMPlex
1453 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1454 
1455   Output Parameter:
1456 . support - An array of points which are on the out-edges for point p
1457 
1458   Level: beginner
1459 
1460 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1461 @*/
1462 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1463 {
1464   DM_Plex    *mesh = (DM_Plex *) dm->data;
1465   PetscInt       off;
1466   PetscErrorCode ierr;
1467 
1468   PetscFunctionBegin;
1469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1470   PetscValidPointer(support, 3);
1471   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1472   *support = &mesh->supports[off];
1473   PetscFunctionReturn(0);
1474 }
1475 
1476 #undef __FUNCT__
1477 #define __FUNCT__ "DMPlexSetSupport"
1478 /*@
1479   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1480 
1481   Not collective
1482 
1483   Input Parameters:
1484 + mesh - The DMPlex
1485 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1486 - support - An array of points which are on the in-edges for point p
1487 
1488   Output Parameter:
1489 
1490   Note:
1491   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1492 
1493   Level: beginner
1494 
1495 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1496 @*/
1497 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1498 {
1499   DM_Plex    *mesh = (DM_Plex *) dm->data;
1500   PetscInt       pStart, pEnd;
1501   PetscInt       dof, off, c;
1502   PetscErrorCode ierr;
1503 
1504   PetscFunctionBegin;
1505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1506   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1507   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1508   if (dof) PetscValidPointer(support, 3);
1509   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1510   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);
1511   for (c = 0; c < dof; ++c) {
1512     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);
1513     mesh->supports[off+c] = support[c];
1514   }
1515   PetscFunctionReturn(0);
1516 }
1517 
1518 #undef __FUNCT__
1519 #define __FUNCT__ "DMPlexInsertSupport"
1520 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1521 {
1522   DM_Plex    *mesh = (DM_Plex *) dm->data;
1523   PetscInt       pStart, pEnd;
1524   PetscInt       dof, off;
1525   PetscErrorCode ierr;
1526 
1527   PetscFunctionBegin;
1528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1529   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1530   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1531   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1532   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);
1533   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);
1534   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);
1535   mesh->supports[off+supportPos] = supportPoint;
1536   PetscFunctionReturn(0);
1537 }
1538 
1539 #undef __FUNCT__
1540 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1541 /*@C
1542   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1543 
1544   Not collective
1545 
1546   Input Parameters:
1547 + mesh - The DMPlex
1548 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1549 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1550 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1551 
1552   Output Parameters:
1553 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1554 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1555 
1556   Note:
1557   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1558 
1559   Level: beginner
1560 
1561 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1562 @*/
1563 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1564 {
1565   DM_Plex     *mesh = (DM_Plex *) dm->data;
1566   PetscInt       *closure, *fifo;
1567   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1568   PetscInt        tmpSize, t;
1569   PetscInt        depth = 0, maxSize;
1570   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1571   PetscErrorCode  ierr;
1572 
1573   PetscFunctionBegin;
1574   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1575   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1576   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1577   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1578   if (*points) {
1579     closure = *points;
1580   } else {
1581     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1582   }
1583   closure[0] = p; closure[1] = 0;
1584   /* This is only 1-level */
1585   if (useCone) {
1586     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1587     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1588     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1589   } else {
1590     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1591     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1592   }
1593   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1594     const PetscInt cp = tmp[t];
1595     const PetscInt co = tmpO ? tmpO[t] : 0;
1596 
1597     closure[closureSize]   = cp;
1598     closure[closureSize+1] = co;
1599     fifo[fifoSize]         = cp;
1600     fifo[fifoSize+1]       = co;
1601   }
1602   while (fifoSize - fifoStart) {
1603     const PetscInt q   = fifo[fifoStart];
1604     const PetscInt o   = fifo[fifoStart+1];
1605     const PetscInt rev = o >= 0 ? 0 : 1;
1606     const PetscInt off = rev ? -(o+1) : o;
1607 
1608     if (useCone) {
1609       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1610       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1611       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1612     } else {
1613       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1614       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1615       tmpO = PETSC_NULL;
1616     }
1617     for (t = 0; t < tmpSize; ++t) {
1618       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1619       const PetscInt cp = tmp[i];
1620       /* Must propogate orientation */
1621       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1622       PetscInt       c;
1623 
1624       /* Check for duplicate */
1625       for (c = 0; c < closureSize; c += 2) {
1626         if (closure[c] == cp) break;
1627       }
1628       if (c == closureSize) {
1629         closure[closureSize]   = cp;
1630         closure[closureSize+1] = co;
1631         fifo[fifoSize]         = cp;
1632         fifo[fifoSize+1]       = co;
1633         closureSize += 2;
1634         fifoSize    += 2;
1635       }
1636     }
1637     fifoStart += 2;
1638   }
1639   if (numPoints) *numPoints = closureSize/2;
1640   if (points)    *points    = closure;
1641   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1642   PetscFunctionReturn(0);
1643 }
1644 
1645 #undef __FUNCT__
1646 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1647 /*@C
1648   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1649 
1650   Not collective
1651 
1652   Input Parameters:
1653 + mesh - The DMPlex
1654 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1655 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1656 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1657 
1658   Output Parameters:
1659 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1660 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1661 
1662   Note:
1663   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1664 
1665   Level: beginner
1666 
1667 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1668 @*/
1669 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1670 {
1671   PetscErrorCode  ierr;
1672 
1673   PetscFunctionBegin;
1674   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1675   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1676   PetscFunctionReturn(0);
1677 }
1678 
1679 #undef __FUNCT__
1680 #define __FUNCT__ "DMPlexGetFaces"
1681 /*
1682   DMPlexGetFaces -
1683 
1684   Note: This will only work for cell-vertex meshes.
1685 */
1686 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1687 {
1688   DM_Plex     *mesh  = (DM_Plex *) dm->data;
1689   const PetscInt *cone  = PETSC_NULL;
1690   PetscInt        depth = 0, dim, coneSize;
1691   PetscErrorCode  ierr;
1692 
1693   PetscFunctionBegin;
1694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1695   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1696   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1697   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1698   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1699   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1700   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1701   switch (dim) {
1702   case 2:
1703     switch (coneSize) {
1704     case 3:
1705       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1706       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1707       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1708       *numFaces = 3;
1709       *faceSize = 2;
1710       *faces    = mesh->facesTmp;
1711       break;
1712     case 4:
1713       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1714       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1715       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1716       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1717       *numFaces = 4;
1718       *faceSize = 2;
1719       *faces    = mesh->facesTmp;
1720       break;
1721     default:
1722       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1723     }
1724     break;
1725   case 3:
1726     switch (coneSize) {
1727     case 3:
1728       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1729       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1730       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1731       *numFaces = 3;
1732       *faceSize = 2;
1733       *faces    = mesh->facesTmp;
1734       break;
1735     case 4:
1736       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1737       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1738       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1739       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1740       *numFaces = 4;
1741       *faceSize = 3;
1742       *faces    = mesh->facesTmp;
1743       break;
1744     default:
1745       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1746     }
1747     break;
1748   default:
1749     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1750   }
1751   PetscFunctionReturn(0);
1752 }
1753 
1754 #undef __FUNCT__
1755 #define __FUNCT__ "DMPlexGetMaxSizes"
1756 /*@
1757   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1758 
1759   Not collective
1760 
1761   Input Parameter:
1762 . mesh - The DMPlex
1763 
1764   Output Parameters:
1765 + maxConeSize - The maximum number of in-edges
1766 - maxSupportSize - The maximum number of out-edges
1767 
1768   Level: beginner
1769 
1770 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1771 @*/
1772 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1773 {
1774   DM_Plex *mesh = (DM_Plex *) dm->data;
1775 
1776   PetscFunctionBegin;
1777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1778   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1779   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1780   PetscFunctionReturn(0);
1781 }
1782 
1783 #undef __FUNCT__
1784 #define __FUNCT__ "DMSetUp_Plex"
1785 PetscErrorCode DMSetUp_Plex(DM dm)
1786 {
1787   DM_Plex    *mesh = (DM_Plex *) dm->data;
1788   PetscInt       size;
1789   PetscErrorCode ierr;
1790 
1791   PetscFunctionBegin;
1792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1793   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1794   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1795   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1796   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1797   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1798   if (mesh->maxSupportSize) {
1799     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1800     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1801     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1802   }
1803   PetscFunctionReturn(0);
1804 }
1805 
1806 #undef __FUNCT__
1807 #define __FUNCT__ "DMCreateSubDM_Plex"
1808 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1809 {
1810   PetscSection   section, sectionGlobal;
1811   PetscInt      *subIndices;
1812   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1813   PetscErrorCode ierr;
1814 
1815   PetscFunctionBegin;
1816   if (!numFields) PetscFunctionReturn(0);
1817   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1818   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1819   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1820   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1821   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1822   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);
1823   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1824   for (p = pStart; p < pEnd; ++p) {
1825     PetscInt gdof;
1826 
1827     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1828     if (gdof > 0) {
1829       for (f = 0; f < numFields; ++f) {
1830         PetscInt fdof, fcdof;
1831 
1832         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1833         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1834         subSize += fdof-fcdof;
1835       }
1836     }
1837   }
1838   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1839   for (p = pStart; p < pEnd; ++p) {
1840     PetscInt gdof, goff;
1841 
1842     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1843     if (gdof > 0) {
1844       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1845       for (f = 0; f < numFields; ++f) {
1846         PetscInt fdof, fcdof, fc, f2, poff = 0;
1847 
1848         /* Can get rid of this loop by storing field information in the global section */
1849         for (f2 = 0; f2 < fields[f]; ++f2) {
1850           ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1851           ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1852           poff += fdof-fcdof;
1853         }
1854         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1855         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1856         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1857           subIndices[subOff] = goff+poff+fc;
1858         }
1859       }
1860     }
1861   }
1862   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1863   if (subdm) {
1864     PetscSection subsection;
1865     PetscBool    haveNull = PETSC_FALSE;
1866     PetscInt     f, nf = 0;
1867 
1868     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1869     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1870     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1871     for (f = 0; f < numFields; ++f) {
1872       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1873       if ((*subdm)->nullspaceConstructors[f]) {
1874         haveNull = PETSC_TRUE;
1875         nf       = f;
1876       }
1877     }
1878     if (haveNull) {
1879       MatNullSpace nullSpace;
1880 
1881       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1882       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1883       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1884     }
1885     if (dm->fields) {
1886       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);
1887       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1888       for (f = 0; f < numFields; ++f) {
1889         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1890       }
1891       if (numFields == 1) {
1892         MatNullSpace space;
1893         Mat          pmat;
1894 
1895         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject *) &space);CHKERRQ(ierr);
1896         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1897         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject *) &space);CHKERRQ(ierr);
1898         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1899         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject *) &pmat);CHKERRQ(ierr);
1900         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1901       }
1902     }
1903   }
1904   PetscFunctionReturn(0);
1905 }
1906 
1907 #undef __FUNCT__
1908 #define __FUNCT__ "DMPlexSymmetrize"
1909 /*@
1910   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1911 
1912   Not collective
1913 
1914   Input Parameter:
1915 . mesh - The DMPlex
1916 
1917   Output Parameter:
1918 
1919   Note:
1920   This should be called after all calls to DMPlexSetCone()
1921 
1922   Level: beginner
1923 
1924 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1925 @*/
1926 PetscErrorCode DMPlexSymmetrize(DM dm)
1927 {
1928   DM_Plex    *mesh = (DM_Plex *) dm->data;
1929   PetscInt      *offsets;
1930   PetscInt       supportSize;
1931   PetscInt       pStart, pEnd, p;
1932   PetscErrorCode ierr;
1933 
1934   PetscFunctionBegin;
1935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1936   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1937   /* Calculate support sizes */
1938   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1939   for (p = pStart; p < pEnd; ++p) {
1940     PetscInt dof, off, c;
1941 
1942     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1943     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1944     for (c = off; c < off+dof; ++c) {
1945       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1946     }
1947   }
1948   for (p = pStart; p < pEnd; ++p) {
1949     PetscInt dof;
1950 
1951     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1952     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1953   }
1954   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1955   /* Calculate supports */
1956   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1957   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1958   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1959   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1960   for (p = pStart; p < pEnd; ++p) {
1961     PetscInt dof, off, c;
1962 
1963     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1964     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1965     for (c = off; c < off+dof; ++c) {
1966       const PetscInt q = mesh->cones[c];
1967       PetscInt       offS;
1968 
1969       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1970       mesh->supports[offS+offsets[q]] = p;
1971       ++offsets[q];
1972     }
1973   }
1974   ierr = PetscFree(offsets);CHKERRQ(ierr);
1975   PetscFunctionReturn(0);
1976 }
1977 
1978 #undef __FUNCT__
1979 #define __FUNCT__ "DMPlexSetDepth_Private"
1980 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1981 {
1982   PetscInt       d;
1983   PetscErrorCode ierr;
1984 
1985   PetscFunctionBegin;
1986   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1987   if (d < 0) {
1988     /* We are guaranteed that the point has a cone since the depth was not yet set */
1989     const PetscInt *cone = PETSC_NULL;
1990     PetscInt        dCone;
1991 
1992     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1993     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1994     d    = dCone+1;
1995     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1996   }
1997   *depth = d;
1998   PetscFunctionReturn(0);
1999 }
2000 
2001 #undef __FUNCT__
2002 #define __FUNCT__ "DMPlexStratify"
2003 /*@
2004   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2005   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2006   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2007   the DAG.
2008 
2009   Not collective
2010 
2011   Input Parameter:
2012 . mesh - The DMPlex
2013 
2014   Output Parameter:
2015 
2016   Notes:
2017   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2018   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2019 
2020   This should be called after all calls to DMPlexSymmetrize()
2021 
2022   Level: beginner
2023 
2024 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2025 @*/
2026 PetscErrorCode DMPlexStratify(DM dm)
2027 {
2028   DM_Plex    *mesh = (DM_Plex *) dm->data;
2029   PetscInt       pStart, pEnd, p;
2030   PetscInt       numRoots = 0, numLeaves = 0;
2031   PetscErrorCode ierr;
2032 
2033   PetscFunctionBegin;
2034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2035   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2036   /* Calculate depth */
2037   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2038   /* Initialize roots and count leaves */
2039   for (p = pStart; p < pEnd; ++p) {
2040     PetscInt coneSize, supportSize;
2041 
2042     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2043     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2044     if (!coneSize && supportSize) {
2045       ++numRoots;
2046       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2047     } else if (!supportSize && coneSize) {
2048       ++numLeaves;
2049     } else if (!supportSize && !coneSize) {
2050       /* Isolated points */
2051       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2052     }
2053   }
2054   if (numRoots + numLeaves == (pEnd - pStart)) {
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 (!supportSize && coneSize) {
2061         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2062       }
2063     }
2064   } else {
2065     /* This might be slow since lookup is not fast */
2066     for (p = pStart; p < pEnd; ++p) {
2067       PetscInt depth;
2068 
2069       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2070     }
2071   }
2072   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2073   PetscFunctionReturn(0);
2074 }
2075 
2076 #undef __FUNCT__
2077 #define __FUNCT__ "DMPlexGetJoin"
2078 /*@C
2079   DMPlexGetJoin - Get an array for the join of the set of points
2080 
2081   Not Collective
2082 
2083   Input Parameters:
2084 + dm - The DMPlex object
2085 . numPoints - The number of input points for the join
2086 - points - The input points
2087 
2088   Output Parameters:
2089 + numCoveredPoints - The number of points in the join
2090 - coveredPoints - The points in the join
2091 
2092   Level: intermediate
2093 
2094   Note: Currently, this is restricted to a single level join
2095 
2096 .keywords: mesh
2097 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2098 @*/
2099 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2100 {
2101   DM_Plex    *mesh = (DM_Plex *) dm->data;
2102   PetscInt      *join[2];
2103   PetscInt       joinSize, i = 0;
2104   PetscInt       dof, off, p, c, m;
2105   PetscErrorCode ierr;
2106 
2107   PetscFunctionBegin;
2108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2109   PetscValidPointer(points, 2);
2110   PetscValidPointer(numCoveredPoints, 3);
2111   PetscValidPointer(coveredPoints, 4);
2112   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2113   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2114   /* Copy in support of first point */
2115   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2116   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2117   for (joinSize = 0; joinSize < dof; ++joinSize) {
2118     join[i][joinSize] = mesh->supports[off+joinSize];
2119   }
2120   /* Check each successive support */
2121   for (p = 1; p < numPoints; ++p) {
2122     PetscInt newJoinSize = 0;
2123 
2124     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2125     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2126     for (c = 0; c < dof; ++c) {
2127       const PetscInt point = mesh->supports[off+c];
2128 
2129       for (m = 0; m < joinSize; ++m) {
2130         if (point == join[i][m]) {
2131           join[1-i][newJoinSize++] = point;
2132           break;
2133         }
2134       }
2135     }
2136     joinSize = newJoinSize;
2137     i = 1-i;
2138   }
2139   *numCoveredPoints = joinSize;
2140   *coveredPoints    = join[i];
2141   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2142   PetscFunctionReturn(0);
2143 }
2144 
2145 #undef __FUNCT__
2146 #define __FUNCT__ "DMPlexRestoreJoin"
2147 /*@C
2148   DMPlexRestoreJoin - Restore an array for the join of the set of points
2149 
2150   Not Collective
2151 
2152   Input Parameters:
2153 + dm - The DMPlex object
2154 . numPoints - The number of input points for the join
2155 - points - The input points
2156 
2157   Output Parameters:
2158 + numCoveredPoints - The number of points in the join
2159 - coveredPoints - The points in the join
2160 
2161   Level: intermediate
2162 
2163 .keywords: mesh
2164 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2165 @*/
2166 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2167 {
2168   PetscErrorCode ierr;
2169 
2170   PetscFunctionBegin;
2171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2172   PetscValidPointer(coveredPoints, 4);
2173   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2174   PetscFunctionReturn(0);
2175 }
2176 
2177 #undef __FUNCT__
2178 #define __FUNCT__ "DMPlexGetFullJoin"
2179 /*@C
2180   DMPlexGetFullJoin - Get an array for the join of the set of points
2181 
2182   Not Collective
2183 
2184   Input Parameters:
2185 + dm - The DMPlex object
2186 . numPoints - The number of input points for the join
2187 - points - The input points
2188 
2189   Output Parameters:
2190 + numCoveredPoints - The number of points in the join
2191 - coveredPoints - The points in the join
2192 
2193   Level: intermediate
2194 
2195 .keywords: mesh
2196 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2197 @*/
2198 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2199 {
2200   DM_Plex    *mesh = (DM_Plex *) dm->data;
2201   PetscInt      *offsets, **closures;
2202   PetscInt      *join[2];
2203   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2204   PetscInt       p, d, c, m;
2205   PetscErrorCode ierr;
2206 
2207   PetscFunctionBegin;
2208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2209   PetscValidPointer(points, 2);
2210   PetscValidPointer(numCoveredPoints, 3);
2211   PetscValidPointer(coveredPoints, 4);
2212 
2213   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2214   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2215   ierr = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2216   ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2217   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2218   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2219   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2220 
2221   for (p = 0; p < numPoints; ++p) {
2222     PetscInt closureSize;
2223 
2224     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2225     offsets[p*(depth+2)+0] = 0;
2226     for (d = 0; d < depth+1; ++d) {
2227       PetscInt pStart, pEnd, i;
2228 
2229       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2230       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2231         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2232           offsets[p*(depth+2)+d+1] = i;
2233           break;
2234         }
2235       }
2236       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2237     }
2238     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);
2239   }
2240   for (d = 0; d < depth+1; ++d) {
2241     PetscInt dof;
2242 
2243     /* Copy in support of first point */
2244     dof = offsets[d+1] - offsets[d];
2245     for (joinSize = 0; joinSize < dof; ++joinSize) {
2246       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2247     }
2248     /* Check each successive cone */
2249     for (p = 1; p < numPoints && joinSize; ++p) {
2250       PetscInt newJoinSize = 0;
2251 
2252       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2253       for (c = 0; c < dof; ++c) {
2254         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2255 
2256         for (m = 0; m < joinSize; ++m) {
2257           if (point == join[i][m]) {
2258             join[1-i][newJoinSize++] = point;
2259             break;
2260           }
2261         }
2262       }
2263       joinSize = newJoinSize;
2264       i = 1-i;
2265     }
2266     if (joinSize) break;
2267   }
2268   *numCoveredPoints = joinSize;
2269   *coveredPoints    = join[i];
2270   for (p = 0; p < numPoints; ++p) {
2271     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2272   }
2273   ierr = PetscFree(closures);CHKERRQ(ierr);
2274   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2275   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2276   PetscFunctionReturn(0);
2277 }
2278 
2279 #undef __FUNCT__
2280 #define __FUNCT__ "DMPlexGetMeet"
2281 /*@C
2282   DMPlexGetMeet - Get an array for the meet of the set of points
2283 
2284   Not Collective
2285 
2286   Input Parameters:
2287 + dm - The DMPlex object
2288 . numPoints - The number of input points for the meet
2289 - points - The input points
2290 
2291   Output Parameters:
2292 + numCoveredPoints - The number of points in the meet
2293 - coveredPoints - The points in the meet
2294 
2295   Level: intermediate
2296 
2297   Note: Currently, this is restricted to a single level meet
2298 
2299 .keywords: mesh
2300 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2301 @*/
2302 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2303 {
2304   DM_Plex    *mesh = (DM_Plex *) dm->data;
2305   PetscInt      *meet[2];
2306   PetscInt       meetSize, i = 0;
2307   PetscInt       dof, off, p, c, m;
2308   PetscErrorCode ierr;
2309 
2310   PetscFunctionBegin;
2311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2312   PetscValidPointer(points, 2);
2313   PetscValidPointer(numCoveringPoints, 3);
2314   PetscValidPointer(coveringPoints, 4);
2315   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2316   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2317   /* Copy in cone of first point */
2318   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2319   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2320   for (meetSize = 0; meetSize < dof; ++meetSize) {
2321     meet[i][meetSize] = mesh->cones[off+meetSize];
2322   }
2323   /* Check each successive cone */
2324   for (p = 1; p < numPoints; ++p) {
2325     PetscInt newMeetSize = 0;
2326 
2327     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2328     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2329     for (c = 0; c < dof; ++c) {
2330       const PetscInt point = mesh->cones[off+c];
2331 
2332       for (m = 0; m < meetSize; ++m) {
2333         if (point == meet[i][m]) {
2334           meet[1-i][newMeetSize++] = point;
2335           break;
2336         }
2337       }
2338     }
2339     meetSize = newMeetSize;
2340     i = 1-i;
2341   }
2342   *numCoveringPoints = meetSize;
2343   *coveringPoints    = meet[i];
2344   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2345   PetscFunctionReturn(0);
2346 }
2347 
2348 #undef __FUNCT__
2349 #define __FUNCT__ "DMPlexRestoreMeet"
2350 /*@C
2351   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2352 
2353   Not Collective
2354 
2355   Input Parameters:
2356 + dm - The DMPlex object
2357 . numPoints - The number of input points for the meet
2358 - points - The input points
2359 
2360   Output Parameters:
2361 + numCoveredPoints - The number of points in the meet
2362 - coveredPoints - The points in the meet
2363 
2364   Level: intermediate
2365 
2366 .keywords: mesh
2367 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2368 @*/
2369 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2370 {
2371   PetscErrorCode ierr;
2372 
2373   PetscFunctionBegin;
2374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2375   PetscValidPointer(coveredPoints, 4);
2376   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2377   PetscFunctionReturn(0);
2378 }
2379 
2380 #undef __FUNCT__
2381 #define __FUNCT__ "DMPlexGetFullMeet"
2382 /*@C
2383   DMPlexGetFullMeet - Get an array for the meet of the set of points
2384 
2385   Not Collective
2386 
2387   Input Parameters:
2388 + dm - The DMPlex object
2389 . numPoints - The number of input points for the meet
2390 - points - The input points
2391 
2392   Output Parameters:
2393 + numCoveredPoints - The number of points in the meet
2394 - coveredPoints - The points in the meet
2395 
2396   Level: intermediate
2397 
2398 .keywords: mesh
2399 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2400 @*/
2401 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2402 {
2403   DM_Plex    *mesh = (DM_Plex *) dm->data;
2404   PetscInt      *offsets, **closures;
2405   PetscInt      *meet[2];
2406   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2407   PetscInt       p, h, c, m;
2408   PetscErrorCode ierr;
2409 
2410   PetscFunctionBegin;
2411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2412   PetscValidPointer(points, 2);
2413   PetscValidPointer(numCoveredPoints, 3);
2414   PetscValidPointer(coveredPoints, 4);
2415 
2416   ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2417   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2418   ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2419   maxSize = PetscPowInt(mesh->maxConeSize,height);
2420   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2421   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2422 
2423   for (p = 0; p < numPoints; ++p) {
2424     PetscInt closureSize;
2425 
2426     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2427     offsets[p*(height+2)+0] = 0;
2428     for (h = 0; h < height+1; ++h) {
2429       PetscInt pStart, pEnd, i;
2430 
2431       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2432       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2433         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2434           offsets[p*(height+2)+h+1] = i;
2435           break;
2436         }
2437       }
2438       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2439     }
2440     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);
2441   }
2442   for (h = 0; h < height+1; ++h) {
2443     PetscInt dof;
2444 
2445     /* Copy in cone of first point */
2446     dof = offsets[h+1] - offsets[h];
2447     for (meetSize = 0; meetSize < dof; ++meetSize) {
2448       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2449     }
2450     /* Check each successive cone */
2451     for (p = 1; p < numPoints && meetSize; ++p) {
2452       PetscInt newMeetSize = 0;
2453 
2454       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2455       for (c = 0; c < dof; ++c) {
2456         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2457 
2458         for (m = 0; m < meetSize; ++m) {
2459           if (point == meet[i][m]) {
2460             meet[1-i][newMeetSize++] = point;
2461             break;
2462           }
2463         }
2464       }
2465       meetSize = newMeetSize;
2466       i = 1-i;
2467     }
2468     if (meetSize) break;
2469   }
2470   *numCoveredPoints = meetSize;
2471   *coveredPoints    = meet[i];
2472   for (p = 0; p < numPoints; ++p) {
2473     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2474   }
2475   ierr = PetscFree(closures);CHKERRQ(ierr);
2476   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2477   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2478   PetscFunctionReturn(0);
2479 }
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2483 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2484 {
2485   MPI_Comm       comm = ((PetscObject) dm)->comm;
2486   PetscInt       cellDim;
2487   PetscErrorCode ierr;
2488 
2489   PetscFunctionBegin;
2490   PetscValidPointer(numFaceVertices,3);
2491   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2492   switch (cellDim) {
2493   case 0:
2494     *numFaceVertices = 0;
2495     break;
2496   case 1:
2497     *numFaceVertices = 1;
2498     break;
2499   case 2:
2500     switch (numCorners) {
2501     case 3: /* triangle */
2502       *numFaceVertices = 2; /* Edge has 2 vertices */
2503       break;
2504     case 4: /* quadrilateral */
2505       *numFaceVertices = 2; /* Edge has 2 vertices */
2506       break;
2507     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2508       *numFaceVertices = 3; /* Edge has 3 vertices */
2509       break;
2510     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2511       *numFaceVertices = 3; /* Edge has 3 vertices */
2512       break;
2513     default:
2514       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2515     }
2516     break;
2517   case 3:
2518     switch (numCorners) {
2519     case 4: /* tetradehdron */
2520       *numFaceVertices = 3; /* Face has 3 vertices */
2521       break;
2522     case 6: /* tet cohesive cells */
2523       *numFaceVertices = 4; /* Face has 4 vertices */
2524       break;
2525     case 8: /* hexahedron */
2526       *numFaceVertices = 4; /* Face has 4 vertices */
2527       break;
2528     case 9: /* tet cohesive Lagrange cells */
2529       *numFaceVertices = 6; /* Face has 6 vertices */
2530       break;
2531     case 10: /* quadratic tetrahedron */
2532       *numFaceVertices = 6; /* Face has 6 vertices */
2533       break;
2534     case 12: /* hex cohesive Lagrange cells */
2535       *numFaceVertices = 6; /* Face has 6 vertices */
2536       break;
2537     case 18: /* quadratic tet cohesive Lagrange cells */
2538       *numFaceVertices = 6; /* Face has 6 vertices */
2539       break;
2540     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2541       *numFaceVertices = 9; /* Face has 9 vertices */
2542       break;
2543     default:
2544       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2545     }
2546     break;
2547   default:
2548     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2549   }
2550   PetscFunctionReturn(0);
2551 }
2552 
2553 #undef __FUNCT__
2554 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2555 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2556 {
2557   const PetscInt maxFaceCases = 30;
2558   PetscInt       numFaceCases = 0;
2559   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2560   PetscInt      *off, *adj;
2561   PetscInt      *neighborCells, *tmpClosure;
2562   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2563   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2564   PetscErrorCode ierr;
2565 
2566   PetscFunctionBegin;
2567   /* For parallel partitioning, I think you have to communicate supports */
2568   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2569   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2570   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2571   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2572   if (cEnd - cStart == 0) {
2573     if (numVertices) *numVertices = 0;
2574     if (offsets)     *offsets     = PETSC_NULL;
2575     if (adjacency)   *adjacency   = PETSC_NULL;
2576     PetscFunctionReturn(0);
2577   }
2578   numCells = cEnd - cStart;
2579   /* Setup face recognition */
2580   {
2581     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 */
2582 
2583     for (c = cStart; c < cEnd; ++c) {
2584       PetscInt corners;
2585 
2586       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2587       if (!cornersSeen[corners]) {
2588         PetscInt nFV;
2589 
2590         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2591         cornersSeen[corners] = 1;
2592         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2593         numFaceVertices[numFaceCases++] = nFV;
2594       }
2595     }
2596   }
2597   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2598   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2599   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2600   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2601   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2602   /* Count neighboring cells */
2603   for (cell = cStart; cell < cEnd; ++cell) {
2604     PetscInt numNeighbors = maxNeighbors, n;
2605 
2606     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2607     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2608     for (n = 0; n < numNeighbors; ++n) {
2609       PetscInt        cellPair[2] = {cell, neighborCells[n]};
2610       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2611       PetscInt        meetSize    = 0;
2612       const PetscInt *meet        = PETSC_NULL;
2613 
2614       if (cellPair[0] == cellPair[1]) continue;
2615       if (!found) {
2616         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2617         if (meetSize) {
2618           PetscInt f;
2619 
2620           for (f = 0; f < numFaceCases; ++f) {
2621             if (numFaceVertices[f] == meetSize) {
2622               found = PETSC_TRUE;
2623               break;
2624             }
2625           }
2626         }
2627         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2628       }
2629       if (found) {
2630         ++off[cell-cStart+1];
2631       }
2632     }
2633   }
2634   /* Prefix sum */
2635   for (cell = 1; cell <= numCells; ++cell) {
2636     off[cell] += off[cell-1];
2637   }
2638   if (adjacency) {
2639     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2640     /* Get neighboring cells */
2641     for (cell = cStart; cell < cEnd; ++cell) {
2642       PetscInt numNeighbors = maxNeighbors, n;
2643       PetscInt cellOffset   = 0;
2644 
2645       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2646       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2647       for (n = 0; n < numNeighbors; ++n) {
2648         PetscInt        cellPair[2] = {cell, neighborCells[n]};
2649         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2650         PetscInt        meetSize    = 0;
2651         const PetscInt *meet        = PETSC_NULL;
2652 
2653         if (cellPair[0] == cellPair[1]) continue;
2654         if (!found) {
2655           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2656           if (meetSize) {
2657             PetscInt f;
2658 
2659             for (f = 0; f < numFaceCases; ++f) {
2660               if (numFaceVertices[f] == meetSize) {
2661                 found = PETSC_TRUE;
2662                 break;
2663               }
2664             }
2665           }
2666           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2667         }
2668         if (found) {
2669           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2670           ++cellOffset;
2671         }
2672       }
2673     }
2674   }
2675   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2676   if (numVertices) *numVertices = numCells;
2677   if (offsets)     *offsets     = off;
2678   if (adjacency)   *adjacency   = adj;
2679   PetscFunctionReturn(0);
2680 }
2681 
2682 #if defined(PETSC_HAVE_CHACO)
2683 #if defined(PETSC_HAVE_UNISTD_H)
2684 #include <unistd.h>
2685 #endif
2686 /* Chaco does not have an include file */
2687 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2688                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2689                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2690                        int mesh_dims[3], double *goal, int global_method, int local_method,
2691                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2692 
2693 extern int FREE_GRAPH;
2694 
2695 #undef __FUNCT__
2696 #define __FUNCT__ "DMPlexPartition_Chaco"
2697 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2698 {
2699   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2700   MPI_Comm comm = ((PetscObject) dm)->comm;
2701   int nvtxs = numVertices;                /* number of vertices in full graph */
2702   int *vwgts = NULL;                      /* weights for all vertices */
2703   float *ewgts = NULL;                    /* weights for all edges */
2704   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2705   char *outassignname = NULL;             /*  name of assignment output file */
2706   char *outfilename = NULL;               /* output file name */
2707   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2708   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2709   int mesh_dims[3];                       /* dimensions of mesh of processors */
2710   double *goal = NULL;                    /* desired set sizes for each set */
2711   int global_method = 1;                  /* global partitioning algorithm */
2712   int local_method = 1;                   /* local partitioning algorithm */
2713   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2714   int vmax = 200;                         /* how many vertices to coarsen down to? */
2715   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2716   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2717   long seed = 123636512;                  /* for random graph mutations */
2718   short int *assignment;                  /* Output partition */
2719   int fd_stdout, fd_pipe[2];
2720   PetscInt      *points;
2721   PetscMPIInt    commSize;
2722   int            i, v, p;
2723   PetscErrorCode ierr;
2724 
2725   PetscFunctionBegin;
2726   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2727   if (!numVertices) {
2728     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2729     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2730     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2731     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2732     PetscFunctionReturn(0);
2733   }
2734   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2735   for (i = 0; i < start[numVertices]; ++i) {
2736     ++adjacency[i];
2737   }
2738   if (global_method == INERTIAL_METHOD) {
2739     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2740     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2741   }
2742   mesh_dims[0] = commSize;
2743   mesh_dims[1] = 1;
2744   mesh_dims[2] = 1;
2745   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2746   /* Chaco outputs to stdout. We redirect this to a buffer. */
2747   /* TODO: check error codes for UNIX calls */
2748 #if defined(PETSC_HAVE_UNISTD_H)
2749   {
2750     int piperet;
2751     piperet = pipe(fd_pipe);
2752     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2753     fd_stdout = dup(1);
2754     close(1);
2755     dup2(fd_pipe[1], 1);
2756   }
2757 #endif
2758   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2759                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2760                    vmax, ndims, eigtol, seed);
2761 #if defined(PETSC_HAVE_UNISTD_H)
2762   {
2763     char msgLog[10000];
2764     int  count;
2765 
2766     fflush(stdout);
2767     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2768     if (count < 0) count = 0;
2769     msgLog[count] = 0;
2770     close(1);
2771     dup2(fd_stdout, 1);
2772     close(fd_stdout);
2773     close(fd_pipe[0]);
2774     close(fd_pipe[1]);
2775     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2776   }
2777 #endif
2778   /* Convert to PetscSection+IS */
2779   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2780   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2781   for (v = 0; v < nvtxs; ++v) {
2782     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2783   }
2784   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2785   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2786   for (p = 0, i = 0; p < commSize; ++p) {
2787     for (v = 0; v < nvtxs; ++v) {
2788       if (assignment[v] == p) points[i++] = v;
2789     }
2790   }
2791   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2792   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2793   if (global_method == INERTIAL_METHOD) {
2794     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2795   }
2796   ierr = PetscFree(assignment);CHKERRQ(ierr);
2797   for (i = 0; i < start[numVertices]; ++i) {
2798     --adjacency[i];
2799   }
2800   PetscFunctionReturn(0);
2801 }
2802 #endif
2803 
2804 #if defined(PETSC_HAVE_PARMETIS)
2805 #undef __FUNCT__
2806 #define __FUNCT__ "DMPlexPartition_ParMetis"
2807 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2808 {
2809   PetscFunctionBegin;
2810   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2811   PetscFunctionReturn(0);
2812 }
2813 #endif
2814 
2815 #undef __FUNCT__
2816 #define __FUNCT__ "DMPlexEnlargePartition"
2817 /* Expand the partition by BFS on the adjacency graph */
2818 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2819 {
2820   PetscHashI      h;
2821   const PetscInt *points;
2822   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2823   PetscInt        pStart, pEnd, part, q;
2824   PetscErrorCode  ierr;
2825 
2826   PetscFunctionBegin;
2827   PetscHashICreate(h);
2828   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2829   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2830   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2831   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2832   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2833   for (part = pStart; part < pEnd; ++part) {
2834     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2835 
2836     PetscHashIClear(h);
2837     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2838     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2839     /* Add all existing points to h */
2840     for (p = 0; p < numPoints; ++p) {
2841       const PetscInt point = points[off+p];
2842       PetscHashIAdd(h, point, 1);
2843     }
2844     PetscHashISize(h, nP);
2845     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2846     /* Add all points in next BFS level */
2847     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2848     for (p = 0; p < numPoints; ++p) {
2849       const PetscInt point = points[off+p];
2850       PetscInt s = start[point], e = start[point+1], a;
2851 
2852       for (a = s; a < e; ++a) {
2853         PetscHashIAdd(h, adjacency[a], 1);
2854       }
2855     }
2856     PetscHashISize(h, numNewPoints);
2857     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2858     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2859     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2860     totPoints += numNewPoints;
2861   }
2862   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2863   PetscHashIDestroy(h);
2864   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2865   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2866   for (part = pStart, q = 0; part < pEnd; ++part) {
2867     PetscInt numPoints, p;
2868 
2869     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2870     for (p = 0; p < numPoints; ++p, ++q) {
2871       newPoints[q] = tmpPoints[part][p];
2872     }
2873     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2874   }
2875   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2876   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2877   PetscFunctionReturn(0);
2878 }
2879 
2880 #undef __FUNCT__
2881 #define __FUNCT__ "DMPlexCreatePartition"
2882 /*
2883   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2884 
2885   Collective on DM
2886 
2887   Input Parameters:
2888   + dm - The DM
2889   . height - The height for points in the partition
2890   - enlarge - Expand each partition with neighbors
2891 
2892   Output Parameters:
2893   + partSection - The PetscSection giving the division of points by partition
2894   . partition - The list of points by partition
2895   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2896   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2897 
2898   Level: developer
2899 
2900 .seealso DMPlexDistribute()
2901 */
2902 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2903 {
2904   PetscMPIInt    size;
2905   PetscErrorCode ierr;
2906 
2907   PetscFunctionBegin;
2908   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2909   *origPartSection = PETSC_NULL;
2910   *origPartition   = PETSC_NULL;
2911   if (size == 1) {
2912     PetscInt *points;
2913     PetscInt  cStart, cEnd, c;
2914 
2915     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2916     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2917     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2918     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2919     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2920     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2921     for (c = cStart; c < cEnd; ++c) {
2922       points[c] = c;
2923     }
2924     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2925     PetscFunctionReturn(0);
2926   }
2927   if (height == 0) {
2928     PetscInt  numVertices;
2929     PetscInt *start     = PETSC_NULL;
2930     PetscInt *adjacency = PETSC_NULL;
2931 
2932     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2933     if (1) {
2934 #if defined(PETSC_HAVE_CHACO)
2935       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2936 #endif
2937     } else {
2938 #if defined(PETSC_HAVE_PARMETIS)
2939       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2940 #endif
2941     }
2942     if (enlarge) {
2943       *origPartSection = *partSection;
2944       *origPartition   = *partition;
2945       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2946     }
2947     ierr = PetscFree(start);CHKERRQ(ierr);
2948     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2949 # if 0
2950   } else if (height == 1) {
2951     /* Build the dual graph for faces and partition the hypergraph */
2952     PetscInt numEdges;
2953 
2954     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2955     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2956     destroyCSR(numEdges, start, adjacency);
2957 #endif
2958   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2959   PetscFunctionReturn(0);
2960 }
2961 
2962 #undef __FUNCT__
2963 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2964 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2965 {
2966   /* const PetscInt  height = 0; */
2967   const PetscInt *partArray;
2968   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2969   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2970   PetscErrorCode  ierr;
2971 
2972   PetscFunctionBegin;
2973   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2974   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2975   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2976   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2977   for (rank = rStart; rank < rEnd; ++rank) {
2978     PetscInt partSize = 0;
2979     PetscInt numPoints, offset, p;
2980 
2981     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2982     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2983     for (p = 0; p < numPoints; ++p) {
2984       PetscInt  point   = partArray[offset+p], closureSize, c;
2985       PetscInt *closure = PETSC_NULL;
2986 
2987       /* TODO Include support for height > 0 case */
2988       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2989       /* Merge into existing points */
2990       if (partSize+closureSize > maxPartSize) {
2991         PetscInt *tmpPoints;
2992 
2993         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2994         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2995         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2996         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2997         partPoints = tmpPoints;
2998       }
2999       for (c = 0; c < closureSize; ++c) {
3000         partPoints[partSize+c] = closure[c*2];
3001       }
3002       partSize += closureSize;
3003       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3004       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3005     }
3006     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3007   }
3008   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3009   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3010   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3011 
3012   for (rank = rStart; rank < rEnd; ++rank) {
3013     PetscInt partSize = 0, newOffset;
3014     PetscInt numPoints, offset, p;
3015 
3016     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3017     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3018     for (p = 0; p < numPoints; ++p) {
3019       PetscInt  point   = partArray[offset+p], closureSize, c;
3020       PetscInt *closure = PETSC_NULL;
3021 
3022       /* TODO Include support for height > 0 case */
3023       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3024       /* Merge into existing points */
3025       for (c = 0; c < closureSize; ++c) {
3026         partPoints[partSize+c] = closure[c*2];
3027       }
3028       partSize += closureSize;
3029       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3030       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3031     }
3032     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3033     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3034   }
3035   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3036   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3037   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3038   PetscFunctionReturn(0);
3039 }
3040 
3041 #undef __FUNCT__
3042 #define __FUNCT__ "DMPlexDistributeField"
3043 /*
3044   Input Parameters:
3045 . originalSection
3046 , originalVec
3047 
3048   Output Parameters:
3049 . newSection
3050 . newVec
3051 */
3052 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3053 {
3054   PetscSF         fieldSF;
3055   PetscInt       *remoteOffsets, fieldSize;
3056   PetscScalar    *originalValues, *newValues;
3057   PetscErrorCode  ierr;
3058 
3059   PetscFunctionBegin;
3060   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3061 
3062   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3063   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3064   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3065 
3066   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3067   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3068   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3069   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3070   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3071   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3072   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3073   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3074   PetscFunctionReturn(0);
3075 }
3076 
3077 #undef __FUNCT__
3078 #define __FUNCT__ "DMPlexDistribute"
3079 /*@C
3080   DMPlexDistribute - Distributes the mesh and any associated sections.
3081 
3082   Not Collective
3083 
3084   Input Parameter:
3085 + dm  - The original DMPlex object
3086 . partitioner - The partitioning package, or NULL for the default
3087 - overlap - The overlap of partitions, 0 is the default
3088 
3089   Output Parameter:
3090 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3091 
3092   Note: If the mesh was not distributed, the return value is PETSC_NULL
3093 
3094   Level: intermediate
3095 
3096 .keywords: mesh, elements
3097 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3098 @*/
3099 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3100 {
3101   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3102   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3103   const PetscInt height = 0;
3104   PetscInt       dim, numRemoteRanks;
3105   IS             origCellPart,        cellPart,        part;
3106   PetscSection   origCellPartSection, cellPartSection, partSection;
3107   PetscSFNode   *remoteRanks;
3108   PetscSF        partSF, pointSF, coneSF;
3109   ISLocalToGlobalMapping renumbering;
3110   PetscSection   originalConeSection, newConeSection;
3111   PetscInt      *remoteOffsets;
3112   PetscInt      *cones, *newCones, newConesSize;
3113   PetscBool      flg;
3114   PetscMPIInt    rank, numProcs, p;
3115   PetscErrorCode ierr;
3116 
3117   PetscFunctionBegin;
3118   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3119   PetscValidPointer(dmParallel,4);
3120   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3121   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3122   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3123   *dmParallel = PETSC_NULL;
3124   if (numProcs == 1) PetscFunctionReturn(0);
3125 
3126   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3127   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3128   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3129   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3130   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3131   if (!rank) {
3132     numRemoteRanks = numProcs;
3133   } else {
3134     numRemoteRanks = 0;
3135   }
3136   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3137   for (p = 0; p < numRemoteRanks; ++p) {
3138     remoteRanks[p].rank  = p;
3139     remoteRanks[p].index = 0;
3140   }
3141   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3142   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3143   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3144   if (flg) {
3145     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3146     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3147     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3148     if (origCellPart) {
3149       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3150       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3151       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3152     }
3153     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3154   }
3155   /* Close the partition over the mesh */
3156   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3157   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3158   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3159   /* Create new mesh */
3160   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3161   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3162   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3163   pmesh = (DM_Plex *) (*dmParallel)->data;
3164   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3165   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3166   if (flg) {
3167     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3168     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3169     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3170     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3171     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3172     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3173   }
3174   /* Distribute cone section */
3175   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3176   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3177   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3178   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3179   {
3180     PetscInt pStart, pEnd, p;
3181 
3182     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3183     for (p = pStart; p < pEnd; ++p) {
3184       PetscInt coneSize;
3185       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3186       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3187     }
3188   }
3189   /* Communicate and renumber cones */
3190   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3191   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3192   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3193   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3194   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3195   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3196   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3197   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3198   if (flg) {
3199     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3200     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3201     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3202     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3203     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3204   }
3205   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3206   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3207   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3208   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3209   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3210   /* Create supports and stratify sieve */
3211   {
3212     PetscInt pStart, pEnd;
3213 
3214     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3215     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3216   }
3217   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3218   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3219   /* Distribute Coordinates */
3220   {
3221     PetscSection originalCoordSection, newCoordSection;
3222     Vec          originalCoordinates, newCoordinates;
3223     const char  *name;
3224 
3225     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3226     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3227     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3228     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3229     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3230     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3231 
3232     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3233     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3234     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3235   }
3236   /* Distribute labels */
3237   {
3238     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3239     PetscInt   numLabels = 0, l;
3240 
3241     /* Bcast number of labels */
3242     while (next) {++numLabels; next = next->next;}
3243     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3244     next = mesh->labels;
3245     for (l = 0; l < numLabels; ++l) {
3246       DMLabel         newLabel;
3247       const PetscInt *partArray;
3248       char           *name;
3249       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3250       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3251       PetscInt        nameSize, s, p;
3252       PetscBool       isdepth;
3253       size_t          len = 0;
3254 
3255       /* Bcast name (could filter for no points) */
3256       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3257       nameSize = len;
3258       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3259       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3260       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3261       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3262       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3263       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3264       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3265       newLabel->name = name;
3266       /* Bcast numStrata (could filter for no points in stratum) */
3267       if (!rank) {newLabel->numStrata = next->numStrata;}
3268       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3269       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3270                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3271                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3272       /* Bcast stratumValues (could filter for no points in stratum) */
3273       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3274       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3275       /* Find size on each process and Scatter */
3276       if (!rank) {
3277         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3278         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3279         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3280         for (s = 0; s < next->numStrata; ++s) {
3281           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3282             const PetscInt point = next->points[p];
3283             PetscInt       proc;
3284 
3285             for (proc = 0; proc < numProcs; ++proc) {
3286               PetscInt dof, off, pPart;
3287 
3288               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3289               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3290               for (pPart = off; pPart < off+dof; ++pPart) {
3291                 if (partArray[pPart] == point) {
3292                   ++stratumSizes[proc*next->numStrata+s];
3293                   break;
3294                 }
3295               }
3296             }
3297           }
3298         }
3299         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3300       }
3301       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3302       /* Calculate stratumOffsets */
3303       newLabel->stratumOffsets[0] = 0;
3304       for (s = 0; s < newLabel->numStrata; ++s) {
3305         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3306       }
3307       /* Pack points and Scatter */
3308       if (!rank) {
3309         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3310         displs[0] = 0;
3311         for (p = 0; p < numProcs; ++p) {
3312           sendcnts[p] = 0;
3313           for (s = 0; s < next->numStrata; ++s) {
3314             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3315           }
3316           offsets[p]  = displs[p];
3317           displs[p+1] = displs[p] + sendcnts[p];
3318         }
3319         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3320         for (s = 0; s < next->numStrata; ++s) {
3321           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3322             const PetscInt point = next->points[p];
3323             PetscInt       proc;
3324 
3325             for (proc = 0; proc < numProcs; ++proc) {
3326               PetscInt dof, off, pPart;
3327 
3328               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3329               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3330               for (pPart = off; pPart < off+dof; ++pPart) {
3331                 if (partArray[pPart] == point) {
3332                   points[offsets[proc]++] = point;
3333                   break;
3334                 }
3335               }
3336             }
3337           }
3338         }
3339       }
3340       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3341       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3342       ierr = PetscFree(points);CHKERRQ(ierr);
3343       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3344       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3345       /* Renumber points */
3346       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3347       /* Sort points */
3348       for (s = 0; s < newLabel->numStrata; ++s) {
3349         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3350       }
3351       /* Insert into list */
3352       if (newNext) {
3353         newNext->next = newLabel;
3354       } else {
3355         pmesh->labels = newLabel;
3356       }
3357       newNext = newLabel;
3358       if (!rank) {next = next->next;}
3359     }
3360   }
3361   /* Cleanup Partition */
3362   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3363   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3364   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3365   ierr = ISDestroy(&part);CHKERRQ(ierr);
3366   /* Create point SF for parallel mesh */
3367   {
3368     const PetscInt *leaves;
3369     PetscSFNode    *remotePoints, *rowners, *lowners;
3370     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3371     PetscInt        pStart, pEnd;
3372 
3373     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3374     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3375     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3376     for (p=0; p<numRoots; p++) {
3377       rowners[p].rank = -1;
3378       rowners[p].index = -1;
3379     }
3380     if (origCellPart) {
3381       /* Make sure cells in the original partition are not assigned to other procs */
3382       const PetscInt *origCells;
3383 
3384       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3385       for (p = 0; p < numProcs; ++p) {
3386         PetscInt dof, off, d;
3387 
3388         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3389         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3390         for (d = off; d < off+dof; ++d) {
3391           rowners[origCells[d]].rank = p;
3392         }
3393       }
3394       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3395     }
3396     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3397     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3398 
3399     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3400     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3401     for (p = 0; p < numLeaves; ++p) {
3402       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3403         lowners[p].rank = rank;
3404         lowners[p].index = leaves ? leaves[p] : p;
3405       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3406         lowners[p].rank = -2;
3407         lowners[p].index = -2;
3408       }
3409     }
3410     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3411       rowners[p].rank = -3;
3412       rowners[p].index = -3;
3413     }
3414     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3415     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3416     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3417     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3418     for (p = 0; p < numLeaves; ++p) {
3419       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3420       if (lowners[p].rank != rank) ++numGhostPoints;
3421     }
3422     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3423     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3424     for (p = 0, gp = 0; p < numLeaves; ++p) {
3425       if (lowners[p].rank != rank) {
3426         ghostPoints[gp]       = leaves ? leaves[p] : p;
3427         remotePoints[gp].rank  = lowners[p].rank;
3428         remotePoints[gp].index = lowners[p].index;
3429         ++gp;
3430       }
3431     }
3432     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3433     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3434     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3435   }
3436   /* Cleanup */
3437   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3438   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3439   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3440   PetscFunctionReturn(0);
3441 }
3442 
3443 #undef __FUNCT__
3444 #define __FUNCT__ "DMPlexRenumber_Private"
3445 /*
3446   Reasons to renumber:
3447 
3448   1) Permute points, e.g. bandwidth reduction (Renumber)
3449 
3450     a) Must not mix strata
3451 
3452   2) Shift numbers for point insertion (Shift)
3453 
3454     a) Want operation brken into parts so that insertion can be interleaved
3455 
3456   renumbering - An IS which provides the new numbering
3457 */
3458 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3459 {
3460   PetscFunctionBegin;
3461   PetscFunctionReturn(0);
3462 }
3463 
3464 #undef __FUNCT__
3465 #define __FUNCT__ "DMPlexShiftPoint_Private"
3466 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3467 {
3468   if (depth < 0) return p;
3469   /* Cells    */ if (p < depthEnd[depth])   return p;
3470   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3471   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3472   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3473 }
3474 
3475 #undef __FUNCT__
3476 #define __FUNCT__ "DMPlexShiftSizes_Private"
3477 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3478 {
3479   PetscInt      *depthEnd;
3480   PetscInt       depth = 0, d, pStart, pEnd, p;
3481   PetscErrorCode ierr;
3482 
3483   PetscFunctionBegin;
3484   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3485   if (depth < 0) PetscFunctionReturn(0);
3486   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3487   /* Step 1: Expand chart */
3488   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3489   for (d = 0; d <= depth; ++d) {
3490     pEnd += depthShift[d];
3491     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3492   }
3493   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3494   /* Step 2: Set cone and support sizes */
3495   for (d = 0; d <= depth; ++d) {
3496     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3497     for (p = pStart; p < pEnd; ++p) {
3498       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3499       PetscInt size;
3500 
3501       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3502       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3503       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3504       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3505     }
3506   }
3507   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3508   PetscFunctionReturn(0);
3509 }
3510 
3511 #undef __FUNCT__
3512 #define __FUNCT__ "DMPlexShiftPoints_Private"
3513 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3514 {
3515   PetscInt      *depthEnd, *newpoints;
3516   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3517   PetscErrorCode ierr;
3518 
3519   PetscFunctionBegin;
3520   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3521   if (depth < 0) PetscFunctionReturn(0);
3522   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3523   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3524   for (d = 0; d <= depth; ++d) {
3525     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3526   }
3527   /* Step 5: Set cones and supports */
3528   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3529   for (p = pStart; p < pEnd; ++p) {
3530     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3531     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3532 
3533     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3534     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3535     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3536     for (i = 0; i < size; ++i) {
3537       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3538     }
3539     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3540     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3541     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3542     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3543     for (i = 0; i < size; ++i) {
3544       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3545     }
3546     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3547   }
3548   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3549   PetscFunctionReturn(0);
3550 }
3551 
3552 #undef __FUNCT__
3553 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3554 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3555 {
3556   PetscSection   coordSection, newCoordSection;
3557   Vec            coordinates, newCoordinates;
3558   PetscScalar   *coords, *newCoords;
3559   PetscInt      *depthEnd, coordSize;
3560   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3561   PetscErrorCode ierr;
3562 
3563   PetscFunctionBegin;
3564   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3565   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3566   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3567   for (d = 0; d <= depth; ++d) {
3568     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3569   }
3570   /* Step 8: Convert coordinates */
3571   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3572   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3573   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3574   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3575   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3576   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3577   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3578   for (v = vStartNew; v < vEndNew; ++v) {
3579     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3580     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3581   }
3582   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3583   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3584   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3585   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3586   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3587   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3588   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3589   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3590   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3591   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3592   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3593   for (v = vStart; v < vEnd; ++v) {
3594     PetscInt dof, off, noff, d;
3595 
3596     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3597     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3598     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3599     for (d = 0; d < dof; ++d) {
3600       newCoords[noff+d] = coords[off+d];
3601     }
3602   }
3603   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3604   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3605   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3606   PetscFunctionReturn(0);
3607 }
3608 
3609 #undef __FUNCT__
3610 #define __FUNCT__ "DMPlexShiftSF_Private"
3611 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3612 {
3613   PetscInt          *depthEnd;
3614   PetscInt           depth = 0, d;
3615   PetscSF            sfPoint, sfPointNew;
3616   const PetscSFNode *remotePoints;
3617   PetscSFNode       *gremotePoints;
3618   const PetscInt    *localPoints;
3619   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3620   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3621   PetscMPIInt        numProcs;
3622   PetscErrorCode     ierr;
3623 
3624   PetscFunctionBegin;
3625   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3626   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3627   for (d = 0; d <= depth; ++d) {
3628     totShift += depthShift[d];
3629     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3630   }
3631   /* Step 9: Convert pointSF */
3632   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3633   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3634   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3635   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3636   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3637   if (numRoots >= 0) {
3638     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3639     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3640     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3641     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3642     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3643     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3644     for (l = 0; l < numLeaves; ++l) {
3645       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3646       gremotePoints[l].rank  = remotePoints[l].rank;
3647       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3648     }
3649     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3650     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3651   }
3652   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3653   PetscFunctionReturn(0);
3654 }
3655 
3656 #undef __FUNCT__
3657 #define __FUNCT__ "DMPlexShiftLabels_Private"
3658 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3659 {
3660   PetscSF        sfPoint;
3661   DMLabel        vtkLabel, ghostLabel;
3662   PetscInt      *depthEnd;
3663   const PetscSFNode *leafRemote;
3664   const PetscInt    *leafLocal;
3665   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3666   PetscMPIInt    rank;
3667   PetscErrorCode ierr;
3668 
3669   PetscFunctionBegin;
3670   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3671   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3672   for (d = 0; d <= depth; ++d) {
3673     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3674   }
3675   /* Step 10: Convert labels */
3676   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3677   for (l = 0; l < numLabels; ++l) {
3678     DMLabel         label, newlabel;
3679     const char     *lname;
3680     PetscBool       isDepth;
3681     IS              valueIS;
3682     const PetscInt *values;
3683     PetscInt        numValues, val;
3684 
3685     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3686     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3687     if (isDepth) continue;
3688     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3689     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3690     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3691     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3692     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3693     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3694     for (val = 0; val < numValues; ++val) {
3695       IS              pointIS;
3696       const PetscInt *points;
3697       PetscInt        numPoints, p;
3698 
3699       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3700       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3701       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3702       for (p = 0; p < numPoints; ++p) {
3703         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3704 
3705         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3706       }
3707       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3708       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3709     }
3710     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3711     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3712   }
3713   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3714   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3715   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3716   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3717   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3718   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3719   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3720   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3721   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3722   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3723   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3724     for (; c < leafLocal[l] && c < cEnd; ++c) {
3725       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3726     }
3727     if (leafLocal[l] >= cEnd) break;
3728     if (leafRemote[l].rank == rank) {
3729       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3730     } else {
3731       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3732     }
3733   }
3734   for (; c < cEnd; ++c) {
3735     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3736   }
3737   if (0) {
3738     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3739     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3740     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3741   }
3742   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3743   for (f = fStart; f < fEnd; ++f) {
3744     PetscInt numCells;
3745 
3746     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3747     if (numCells < 2) {
3748       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3749     } else {
3750       const PetscInt *cells = PETSC_NULL;
3751       PetscInt        vA, vB;
3752 
3753       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3754       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3755       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3756       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3757     }
3758   }
3759   if (0) {
3760     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3761     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3762     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3763   }
3764   PetscFunctionReturn(0);
3765 }
3766 
3767 #undef __FUNCT__
3768 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3769 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3770 {
3771   DMLabel         label;
3772   IS              valueIS;
3773   const PetscInt *values;
3774   PetscInt       *depthShift;
3775   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3776   PetscErrorCode  ierr;
3777 
3778   PetscFunctionBegin;
3779   /* Count ghost cells */
3780   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3781   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3782   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3783   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3784   *numGhostCells = 0;
3785   for (fs = 0; fs < numFS; ++fs) {
3786     PetscInt numBdFaces;
3787 
3788     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3789     *numGhostCells += numBdFaces;
3790   }
3791   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3792   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3793   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3794   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3795   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3796   /* Step 3: Set cone/support sizes for new points */
3797   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3798   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3799     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3800   }
3801   for (fs = 0; fs < numFS; ++fs) {
3802     IS              faceIS;
3803     const PetscInt *faces;
3804     PetscInt        numFaces, f;
3805 
3806     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3807     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3808     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3809     for (f = 0; f < numFaces; ++f) {
3810       PetscInt size;
3811 
3812       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3813       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3814       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3815     }
3816     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3817     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3818   }
3819   /* Step 4: Setup ghosted DM */
3820   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3821   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3822   /* Step 6: Set cones and supports for new points */
3823   ghostCell = cEnd;
3824   for (fs = 0; fs < numFS; ++fs) {
3825     IS              faceIS;
3826     const PetscInt *faces;
3827     PetscInt        numFaces, f;
3828 
3829     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3830     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3831     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3832     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3833       PetscInt newFace = faces[f] + *numGhostCells;
3834 
3835       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3836       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3837     }
3838     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3839     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3840   }
3841   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3842   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3843   /* Step 7: Stratify */
3844   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3845   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3846   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3847   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3848   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3849   PetscFunctionReturn(0);
3850 }
3851 
3852 #undef __FUNCT__
3853 #define __FUNCT__ "DMPlexConstructGhostCells"
3854 /*@C
3855   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3856 
3857   Collective on dm
3858 
3859   Input Parameters:
3860 + dm - The original DM
3861 - labelName - The label specifying the boundary faces (this could be auto-generated)
3862 
3863   Output Parameters:
3864 + numGhostCells - The number of ghost cells added to the DM
3865 - dmGhosted - The new DM
3866 
3867   Level: developer
3868 
3869 .seealso: DMCreate()
3870 */
3871 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3872 {
3873   DM             gdm;
3874   PetscInt       dim;
3875   PetscErrorCode ierr;
3876 
3877   PetscFunctionBegin;
3878   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3879   PetscValidPointer(numGhostCells, 3);
3880   PetscValidPointer(dmGhosted, 4);
3881   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3882   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3883   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3884   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3885   switch (dim) {
3886   case 2:
3887     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3888     break;
3889   default:
3890     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3891   }
3892   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3893   *dmGhosted = gdm;
3894   PetscFunctionReturn(0);
3895 }
3896 
3897 #undef __FUNCT__
3898 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3899 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, const char labelName[], DM sdm)
3900 {
3901   MPI_Comm        comm = ((PetscObject) dm)->comm;
3902   DMLabel         label;
3903   IS              valueIS, svIS = PETSC_NULL, seIS = PETSC_NULL;
3904   const PetscInt *values, *splitVertices = PETSC_NULL, *splitEdges = PETSC_NULL;
3905   PetscSection    coordSection;
3906   Vec             coordinates;
3907   PetscScalar    *coords;
3908   PetscInt       *depthShift, *depthOffset, *pMaxNew, *coneNew, *supportNew;
3909   PetscInt        shift = 100, depth = 0, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numSplitVertices = 0, v, numSplitEdges = 0, numLabels, l;
3910   PetscErrorCode  ierr;
3911 
3912   PetscFunctionBegin;
3913   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3914   /* Count split points and add cohesive cells */
3915   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3916   if (label) {
3917     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3918     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3919     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3920     ierr = DMLabelGetStratumIS(label, 0, &svIS);CHKERRQ(ierr);
3921     if (svIS) {
3922       ierr = ISGetLocalSize(svIS, &numSplitVertices);CHKERRQ(ierr);
3923       ierr = ISGetIndices(svIS, &splitVertices);CHKERRQ(ierr);
3924     }
3925     ierr = DMLabelGetStratumIS(label, 1, &seIS);CHKERRQ(ierr);
3926     if (seIS) {
3927       ierr = ISGetLocalSize(seIS, &numSplitEdges);CHKERRQ(ierr);
3928       ierr = ISGetIndices(seIS, &splitEdges);CHKERRQ(ierr);
3929     }
3930   }
3931   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3932   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3933   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3934   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3935   for(d = 0; d <= depth; ++d) {
3936     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3937   }
3938   for(sp = 0; sp < numSP; ++sp) {
3939     if ((values[sp] < 0) || (values[sp] > depth)) continue;
3940     ierr = DMLabelGetStratumSize(label, values[sp], &depthShift[values[sp]]);CHKERRQ(ierr);
3941   }
3942   if (depth >= 0) {
3943     /* Calculate number of additional points */
3944     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3945     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3946     /* Calculate hybrid bound for each dimension */
3947     pMaxNew[0]       += depthShift[depth];
3948     if (depth > 1) {pMaxNew[dim-1] += depthShift[depth] + depthShift[0];}
3949     if (depth > 2) {pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];}
3950     /* Calculate point offset for each dimension */
3951     depthOffset[depth] = 0;
3952     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3953     if (depth > 1) {depthOffset[dim-1] = depthOffset[0]     + depthShift[0];}
3954     if (depth > 2) {depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];}
3955   }
3956   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3957   /* Step 3: Set cone/support sizes for new points */
3958   for(sp = 0; sp < numSP; ++sp) {
3959     const PetscInt  dep = values[sp];
3960     const PetscInt *points;
3961     IS              dimIS;
3962     PetscInt        numPoints, p;
3963 
3964     if ((values[sp] < 0) || (values[sp] > depth)) continue;
3965     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
3966     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
3967     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
3968     for(p = 0; p < numPoints; ++p) {
3969       const PetscInt  oldp   = points[p];
3970       const PetscInt  newp   = depthOffset[dep] + oldp;
3971       const PetscInt  splitp = pMaxNew[dep] + p;
3972       const PetscInt *support;
3973       PetscInt        coneSize, supportSize, q, e;
3974 
3975       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3976       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3977       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3978       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3979       if (dep == depth-1) {
3980         const PetscInt ccell = pMaxNew[depth] + p;
3981         /* Add cohesive cells, they are prisms */
3982         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3983       } else if (dep == 0) {
3984         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3985 
3986         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3987         /* Split old vertex: Edges in old split faces and new cohesive edge */
3988         for(e = 0, q = 0; e < supportSize; ++e) {
3989           PetscInt val;
3990 
3991           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3992           if ((val == 1) || (val == (shift + 1))) ++q;
3993         }
3994         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3995         /* Split new vertex: Edges in new split faces and new cohesive edge */
3996         for(e = 0, q = 0; e < supportSize; ++e) {
3997           PetscInt val;
3998 
3999           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4000           if ((val == 1) || (val == -(shift + 1))) ++q;
4001         }
4002         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
4003         /* Add cohesive edges */
4004         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
4005         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4006       }
4007     }
4008     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4009     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4010   }
4011   /* Step 4: Setup split DM */
4012   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4013   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4014   /* Step 6: Set cones and supports for new points */
4015   for(sp = 0; sp < numSP; ++sp) {
4016     const PetscInt  dep = values[sp];
4017     const PetscInt *points;
4018     IS              dimIS;
4019     PetscInt        numPoints, p;
4020 
4021     if ((values[sp] < 0) || (values[sp] > depth)) continue;
4022     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
4023     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4024     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4025     for(p = 0; p < numPoints; ++p) {
4026       const PetscInt  newp   = depthOffset[dep] + points[p];
4027       const PetscInt  splitp = pMaxNew[dep] + p;
4028       const PetscInt *cone, *support;
4029       PetscInt        coneSize, supportSize, q, v, e, s;
4030 
4031       ierr = DMPlexGetConeSize(dm, points[p], &coneSize);CHKERRQ(ierr);
4032       ierr = DMPlexGetCone(dm, points[p], &cone);CHKERRQ(ierr);
4033       ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4034       ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4035       if (dep == depth-1) {
4036         const PetscInt  ccell = pMaxNew[depth] + p;
4037         const PetscInt *supportF;
4038 
4039         /* Split face:       copy in old face to new face to start */
4040         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4041         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4042         /* Split old face:   old vertices in cone so no change */
4043         /* Split new face:   new vertices in cone */
4044         for(q = 0; q < coneSize; ++q) {
4045           ierr = PetscFindInt(cone[q], numSplitVertices, splitVertices, &v);CHKERRQ(ierr);
4046           coneNew[2+q] = pMaxNew[0] + v;
4047         }
4048         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4049         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4050         coneNew[0] = newp;
4051         coneNew[1] = splitp;
4052         for(q = 0; q < coneSize; ++q) {
4053           coneNew[2+q] = (pMaxNew[1] - pMaxNew[0]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4054         }
4055         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4056         for(s = 0; s < supportSize; ++s) {
4057           PetscInt val;
4058 
4059           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4060           if (val < 0) {
4061             const PetscInt *scone;
4062             PetscInt        sconeSize, sc;
4063 
4064             /* Split old face:   Replace negative side cell with cohesive cell */
4065             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4066             /* Negative cell: replace split face */
4067             ierr = DMPlexGetConeSize(sdm, support[s], &sconeSize);CHKERRQ(ierr);
4068             ierr = DMPlexGetCone(sdm, support[s], &scone);CHKERRQ(ierr);
4069             for(sc = 0; sc < sconeSize; ++sc) {
4070               if (scone[sc] == newp) {
4071                 ierr = DMPlexInsertCone(sdm, support[s], sc, splitp);CHKERRQ(ierr);
4072                 break;
4073               }
4074             }
4075           } else {
4076             /* Split new face:   Replace positive side cell with cohesive cell */
4077             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4078           }
4079         }
4080       } else if (dep == 0) {
4081         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4082 
4083         /* Split old vertex: Edges in old split faces and new cohesive edge */
4084         for(e = 0, q = 0; e < supportSize; ++e) {
4085           PetscInt val;
4086 
4087           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4088           if ((val == 1) || (val == (shift + 1))) {
4089             supportNew[q++] = depthOffset[1] + support[e];
4090           }
4091         }
4092         supportNew[q] = cedge;
4093         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4094         /* Split new vertex: Edges in new split faces and new cohesive edge */
4095         for(e = 0, q = 0; e < supportSize; ++e) {
4096           PetscInt val, edge;
4097 
4098           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4099           if (val == 1) {
4100             ierr = PetscFindInt(support[e], numSplitEdges, splitEdges, &edge);CHKERRQ(ierr);
4101             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4102             supportNew[q++] = pMaxNew[1] + edge;
4103           } else if (val == -(shift + 1)) {
4104             const PetscInt *scone;
4105             PetscInt        sconeSize, sc;
4106 
4107             supportNew[q++] = depthOffset[1] + support[e];
4108             /* Negative edge: replace split vertex */
4109             ierr = DMPlexGetConeSize(sdm, depthOffset[1] + support[e], &sconeSize);CHKERRQ(ierr);
4110             ierr = DMPlexGetCone(sdm, depthOffset[1] + support[e], &scone);CHKERRQ(ierr);
4111             for(sc = 0; sc < sconeSize; ++sc) {
4112               if (scone[sc] == newp) {
4113                 ierr = DMPlexInsertCone(sdm, depthOffset[1] + support[e], sc, splitp);CHKERRQ(ierr);
4114                 break;
4115               }
4116             }
4117             if (sc == sconeSize) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Edge %d does not contain split vertex %d", support[e], newp);
4118           }
4119         }
4120         supportNew[q] = cedge;
4121         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4122         /* Cohesive edge:    Old and new split vertex, punting on support */
4123         coneNew[0] = newp;
4124         coneNew[1] = splitp;
4125         ierr = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4126       }
4127     }
4128     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4129     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4130   }
4131   /* Step 7: Stratify */
4132   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4133   /* Step 8: Coordinates */
4134   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4135   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4136   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4137   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4138   for(v = 0; v < numSplitVertices; ++v) {
4139     const PetscInt newp   = depthOffset[0] + splitVertices[v];
4140     const PetscInt splitp = pMaxNew[0] + v;
4141     PetscInt       dof, off, soff, d;
4142 
4143     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4144     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4145     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4146     for(d = 0; d < dof; ++d) {
4147       coords[soff+d] = coords[off+d];
4148     }
4149   }
4150   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4151   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4152   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4153   /* Step 10: Labels */
4154   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4155   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4156   for(sp = 0; sp < numSP; ++sp) {
4157     const PetscInt  dep = values[sp];
4158     const PetscInt *points;
4159     IS              dimIS;
4160     PetscInt        numPoints, p;
4161 
4162     if ((values[sp] < 0) || (values[sp] > depth)) continue;
4163     ierr = DMLabelGetStratumIS(label, dep, &dimIS);CHKERRQ(ierr);
4164     ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4165     ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4166     for(p = 0; p < numPoints; ++p) {
4167       const PetscInt newp   = depthOffset[dep] + points[p];
4168       const PetscInt splitp = pMaxNew[dep] + p;
4169 
4170       for (l = 0; l < numLabels; ++l) {
4171         DMLabel     label;
4172         const char *lname;
4173         PetscInt    val;
4174 
4175         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4176         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4177         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4178         if (val >= 0) {
4179           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4180           if (dep == 0) {
4181             const PetscInt cedge  = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4182             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4183           }
4184         }
4185       }
4186     }
4187     ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4188     ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4189   }
4190   if (label) {
4191     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4192     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4193   }
4194   if (svIS) {ierr = ISRestoreIndices(svIS, &splitVertices);CHKERRQ(ierr);}
4195   if (seIS) {ierr = ISRestoreIndices(seIS, &splitEdges);CHKERRQ(ierr);}
4196   ierr = ISDestroy(&svIS);CHKERRQ(ierr);
4197   ierr = ISDestroy(&seIS);CHKERRQ(ierr);
4198   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4199   PetscFunctionReturn(0);
4200 }
4201 
4202 #undef __FUNCT__
4203 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4204 /*@C
4205   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4206 
4207   Collective on dm
4208 
4209   Input Parameters:
4210 + dm - The original DM
4211 - labelName - The label specifying the boundary faces (this could be auto-generated)
4212 
4213   Output Parameters:
4214 - dmSplit - The new DM
4215 
4216   Level: developer
4217 
4218 .seealso: DMCreate()
4219 */
4220 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4221 {
4222   DM             sdm;
4223   PetscInt       dim;
4224   PetscErrorCode ierr;
4225 
4226   PetscFunctionBegin;
4227   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4228   PetscValidPointer(dmSplit, 4);
4229   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4230   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4231   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4232   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4233   switch(dim) {
4234   case 2:
4235   case 3:
4236     ierr = DMPlexConstructCohesiveCells_Private(dm, labelName, sdm);CHKERRQ(ierr);
4237     break;
4238   default:
4239     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4240   }
4241   *dmSplit = sdm;
4242   PetscFunctionReturn(0);
4243 }
4244 
4245 #undef __FUNCT__
4246 #define __FUNCT__ "DMLabelCohesiveComplete"
4247 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4248 {
4249   IS              dimIS;
4250   const PetscInt *points;
4251   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4252   PetscErrorCode  ierr;
4253 
4254   PetscFunctionBegin;
4255   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4256   /* Cell orientation for face gives the side of the fault */
4257   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4258   if (!dimIS) PetscFunctionReturn(0);
4259   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4260   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4261   for(p = 0; p < numPoints; ++p) {
4262     const PetscInt *support;
4263     PetscInt        supportSize, s;
4264 
4265     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4266     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4267     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4268     for(s = 0; s < supportSize; ++s) {
4269       const PetscInt *cone, *ornt;
4270       PetscInt        coneSize, c;
4271       PetscBool       pos = PETSC_TRUE;
4272 
4273       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4274       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4275       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4276       for(c = 0; c < coneSize; ++c) {
4277         if (cone[c] == points[p]) {
4278           if (ornt[c] >= 0) {
4279             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4280           } else {
4281             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4282             pos  = PETSC_FALSE;
4283           }
4284           break;
4285         }
4286       }
4287       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]);
4288       /* Put faces touching the fault in the label */
4289       for(c = 0; c < coneSize; ++c) {
4290         const PetscInt point = cone[c];
4291 
4292         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4293         if (val == -1) {
4294           PetscInt *closure = PETSC_NULL;
4295           PetscInt  closureSize, cl;
4296 
4297           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4298           for (cl = 0; cl < closureSize*2; cl += 2) {
4299             const PetscInt clp = closure[cl];
4300 
4301             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4302             if ((val >= 0) && (val < dim-1)) {
4303               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4304               break;
4305             }
4306           }
4307           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4308         }
4309       }
4310     }
4311   }
4312   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4313   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4314   /* Search for other cells/faces/edges connected to the fault by a vertex */
4315   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4316   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4317   if (!dimIS) PetscFunctionReturn(0);
4318   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4319   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4320   for(p = 0; p < numPoints; ++p) {
4321     PetscInt *star = PETSC_NULL;
4322     PetscInt  starSize, s;
4323     PetscInt  again = 1; /* 0: Finished 1: Keep iterating after a change 2: No change */
4324 
4325     /* First mark cells connected to the fault */
4326     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4327     while (again) {
4328       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4329       again = 0;
4330       for (s = 0; s < starSize*2; s += 2) {
4331         const PetscInt  point = star[s];
4332         const PetscInt *cone;
4333         PetscInt        coneSize, c;
4334 
4335         if ((point < cStart) || (point >= cEnd)) continue;
4336         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4337         if (val != -1) continue;
4338         again = 2;
4339         ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4340         ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4341         for(c = 0; c < coneSize; ++c) {
4342           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4343           if (val != -1) {
4344             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);
4345             if (val > 0) {
4346               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4347             } else {
4348               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4349             }
4350             again = 1;
4351             break;
4352           }
4353         }
4354       }
4355     }
4356     /* Classify the rest by cell membership */
4357     for (s = 0; s < starSize*2; s += 2) {
4358       const PetscInt point = star[s];
4359 
4360       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4361       if (val == -1) {
4362         PetscInt *sstar = PETSC_NULL;
4363         PetscInt  sstarSize, ss;
4364         PetscBool marked = PETSC_FALSE;
4365 
4366         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4367         for (ss = 0; ss < sstarSize*2; ss += 2) {
4368           const PetscInt spoint = sstar[ss];
4369 
4370           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4371           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4372           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4373           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4374           if (val > 0) {
4375             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4376           } else {
4377             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4378           }
4379           marked = PETSC_TRUE;
4380           break;
4381         }
4382         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4383         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4384       }
4385     }
4386     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4387   }
4388   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4389   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4390   PetscFunctionReturn(0);
4391 }
4392 
4393 #undef __FUNCT__
4394 #define __FUNCT__ "DMPlexInterpolate_2D"
4395 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4396 {
4397   DM             idm;
4398   DM_Plex       *mesh;
4399   PetscHashIJ    edgeTable;
4400   PetscInt      *off;
4401   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4402   PetscInt       numEdges, firstEdge, edge, e;
4403   PetscErrorCode ierr;
4404 
4405   PetscFunctionBegin;
4406   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4407   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4408   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4409   numCells    = cEnd - cStart;
4410   numVertices = vEnd - vStart;
4411   firstEdge   = numCells + numVertices;
4412   numEdges    = 0 ;
4413   /* Count edges using algorithm from CreateNeighborCSR */
4414   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4415   if (off) {
4416     PetscInt numCorners = 0;
4417 
4418     numEdges = off[numCells]/2;
4419 #if 0
4420     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4421     numEdges += 3*numCells - off[numCells];
4422 #else
4423     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4424     for (c = cStart; c < cEnd; ++c) {
4425       PetscInt coneSize;
4426 
4427       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4428       numCorners += coneSize;
4429     }
4430     numEdges += numCorners - off[numCells];
4431 #endif
4432   }
4433 #if 0
4434   /* Check Euler characteristic V - E + F = 1 */
4435   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4436 #endif
4437   /* Create interpolated mesh */
4438   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4439   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4440   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4441   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4442   for (c = 0; c < numCells; ++c) {
4443     PetscInt numCorners;
4444 
4445     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4446     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4447   }
4448   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4449     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4450   }
4451   ierr = DMSetUp(idm);CHKERRQ(ierr);
4452   /* Get edge cones from subsets of cell vertices */
4453   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4454   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4455 
4456   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4457     const PetscInt *cellFaces;
4458     PetscInt        numCellFaces, faceSize, cf;
4459 
4460     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4461     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4462     for (cf = 0; cf < numCellFaces; ++cf) {
4463 #if 1
4464       PetscHashIJKey key = {PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]),
4465                             PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1])};
4466 
4467       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4468       if (e < 0) {
4469         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4470         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4471         e    = edge++;
4472       }
4473 #else
4474       PetscBool found = PETSC_FALSE;
4475 
4476       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4477       for (e = firstEdge; e < edge; ++e) {
4478         const PetscInt *cone;
4479 
4480         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4481         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4482             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4483           found = PETSC_TRUE;
4484           break;
4485         }
4486       }
4487       if (!found) {
4488         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4489         ++edge;
4490       }
4491 #endif
4492       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4493     }
4494   }
4495   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4496   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4497   ierr = PetscFree(off);CHKERRQ(ierr);
4498   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4499   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4500   mesh = (DM_Plex *) (idm)->data;
4501   /* Orient edges */
4502   for (c = 0; c < numCells; ++c) {
4503     const PetscInt *cone = PETSC_NULL, *cellFaces;
4504     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4505 
4506     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4507     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4508     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4509     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4510     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4511     for (cf = 0; cf < numCellFaces; ++cf) {
4512       const PetscInt *econe = PETSC_NULL;
4513       PetscInt        esize;
4514 
4515       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4516       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4517       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]);
4518       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4519         /* Correctly oriented */
4520         mesh->coneOrientations[coff+cf] = 0;
4521       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4522         /* Start at index 1, and reverse orientation */
4523         mesh->coneOrientations[coff+cf] = -(1+1);
4524       }
4525     }
4526   }
4527   *dmInt  = idm;
4528   PetscFunctionReturn(0);
4529 }
4530 
4531 #undef __FUNCT__
4532 #define __FUNCT__ "DMPlexInterpolate_3D"
4533 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4534 {
4535   DM             idm, fdm;
4536   DM_Plex    *mesh;
4537   PetscInt      *off;
4538   const PetscInt numCorners = 4;
4539   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4540   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4541   PetscErrorCode ierr;
4542 
4543   PetscFunctionBegin;
4544   {
4545     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4546     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4547     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4548   }
4549   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4550   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4551   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4552   numCells    = cEnd - cStart;
4553   numVertices = vEnd - vStart;
4554   firstFace   = numCells + numVertices;
4555   numFaces    = 0 ;
4556   /* Count faces using algorithm from CreateNeighborCSR */
4557   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4558   if (off) {
4559     numFaces = off[numCells]/2;
4560     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4561     numFaces += 4*numCells - off[numCells];
4562   }
4563   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4564   firstEdge = firstFace + numFaces;
4565   numEdges  = numVertices + numFaces - numCells - 1;
4566   /* Create interpolated mesh */
4567   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4568   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4569   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4570   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4571   for (c = 0; c < numCells; ++c) {
4572     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4573   }
4574   for (f = firstFace; f < firstFace+numFaces; ++f) {
4575     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4576   }
4577   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4578     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4579   }
4580   ierr = DMSetUp(idm);CHKERRQ(ierr);
4581   /* Get face cones from subsets of cell vertices */
4582   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4583   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4584   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4585   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4586   for (f = firstFace; f < firstFace+numFaces; ++f) {
4587     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4588   }
4589   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4590   for (c = 0, face = firstFace; c < numCells; ++c) {
4591     const PetscInt *cellFaces;
4592     PetscInt        numCellFaces, faceSize, cf;
4593 
4594     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4595     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4596     for (cf = 0; cf < numCellFaces; ++cf) {
4597       PetscBool found = PETSC_FALSE;
4598 
4599       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4600       for (f = firstFace; f < face; ++f) {
4601         const PetscInt *cone = PETSC_NULL;
4602 
4603         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4604         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4605             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4606             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4607             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4608             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4609             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4610           found = PETSC_TRUE;
4611           break;
4612         }
4613       }
4614       if (!found) {
4615         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4616         /* Save the vertices for orientation calculation */
4617         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4618         ++face;
4619       }
4620       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4621     }
4622   }
4623   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4624   /* Get edge cones from subsets of face vertices */
4625   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4626     const PetscInt *cellFaces;
4627     PetscInt        numCellFaces, faceSize, cf;
4628 
4629     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4630     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4631     for (cf = 0; cf < numCellFaces; ++cf) {
4632       PetscBool found = PETSC_FALSE;
4633 
4634       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4635       for (e = firstEdge; e < edge; ++e) {
4636         const PetscInt *cone = PETSC_NULL;
4637 
4638         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4639         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4640             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4641           found = PETSC_TRUE;
4642           break;
4643         }
4644       }
4645       if (!found) {
4646         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4647         ++edge;
4648       }
4649       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4650     }
4651   }
4652   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4653   ierr = PetscFree(off);CHKERRQ(ierr);
4654   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4655   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4656   mesh = (DM_Plex *) (idm)->data;
4657   /* Orient edges */
4658   for (f = firstFace; f < firstFace+numFaces; ++f) {
4659     const PetscInt *cone, *cellFaces;
4660     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4661 
4662     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4663     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4664     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4665     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4666     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4667     for (cf = 0; cf < numCellFaces; ++cf) {
4668       const PetscInt *econe;
4669       PetscInt        esize;
4670 
4671       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4672       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4673       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]);
4674       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4675         /* Correctly oriented */
4676         mesh->coneOrientations[coff+cf] = 0;
4677       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4678         /* Start at index 1, and reverse orientation */
4679         mesh->coneOrientations[coff+cf] = -(1+1);
4680       }
4681     }
4682   }
4683   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4684   /* Orient faces */
4685   for (c = 0; c < numCells; ++c) {
4686     const PetscInt *cone, *cellFaces;
4687     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4688 
4689     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4690     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4691     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4692     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4693     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4694     for (cf = 0; cf < numCellFaces; ++cf) {
4695       PetscInt *origClosure = PETSC_NULL, *closure;
4696       PetscInt  closureSize, i;
4697 
4698       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4699       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4700       for (i = 4; i < 7; ++i) {
4701         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);
4702       }
4703       closure = &origClosure[4*2];
4704       /* Remember that this is the orientation for edges, not vertices */
4705       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4706         /* Correctly oriented */
4707         mesh->coneOrientations[coff+cf] = 0;
4708       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4709         /* Shifted by 1 */
4710         mesh->coneOrientations[coff+cf] = 1;
4711       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4712         /* Shifted by 2 */
4713         mesh->coneOrientations[coff+cf] = 2;
4714       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4715         /* Start at edge 1, and reverse orientation */
4716         mesh->coneOrientations[coff+cf] = -(1+1);
4717       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4718         /* Start at index 0, and reverse orientation */
4719         mesh->coneOrientations[coff+cf] = -(0+1);
4720       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4721         /* Start at index 2, and reverse orientation */
4722         mesh->coneOrientations[coff+cf] = -(2+1);
4723       } 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);
4724       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4725     }
4726   }
4727   {
4728     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4729     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4730     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4731   }
4732   *dmInt  = idm;
4733   PetscFunctionReturn(0);
4734 }
4735 
4736 #undef __FUNCT__
4737 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4738 /*
4739   This takes as input the common mesh generator output, a list of the vertices for each cell
4740 */
4741 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4742 {
4743   PetscInt      *cone, c, p;
4744   PetscErrorCode ierr;
4745 
4746   PetscFunctionBegin;
4747   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4748   for (c = 0; c < numCells; ++c) {
4749     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4750   }
4751   ierr = DMSetUp(dm);CHKERRQ(ierr);
4752   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4753   for (c = 0; c < numCells; ++c) {
4754     for (p = 0; p < numCorners; ++p) {
4755       cone[p] = cells[c*numCorners+p]+numCells;
4756     }
4757     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4758   }
4759   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4760   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4761   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4762   PetscFunctionReturn(0);
4763 }
4764 
4765 #undef __FUNCT__
4766 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4767 /*
4768   This takes as input the coordinates for each vertex
4769 */
4770 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4771 {
4772   PetscSection   coordSection;
4773   Vec            coordinates;
4774   PetscScalar   *coords;
4775   PetscInt       coordSize, v, d;
4776   PetscErrorCode ierr;
4777 
4778   PetscFunctionBegin;
4779   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4780   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4781   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4782   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4783   for (v = numCells; v < numCells+numVertices; ++v) {
4784     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4785     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4786   }
4787   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4788   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4789   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4790   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4791   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4792   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4793   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4794   for (v = 0; v < numVertices; ++v) {
4795     for (d = 0; d < spaceDim; ++d) {
4796       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4797     }
4798   }
4799   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4800   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4801   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4802   PetscFunctionReturn(0);
4803 }
4804 
4805 #undef __FUNCT__
4806 #define __FUNCT__ "DMPlexCreateFromCellList"
4807 /*
4808   This takes as input the common mesh generator output, a list of the vertices for each cell
4809 */
4810 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4811 {
4812   PetscErrorCode ierr;
4813 
4814   PetscFunctionBegin;
4815   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4816   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4817   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4818   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4819   if (interpolate) {
4820     DM idm;
4821 
4822     switch (dim) {
4823     case 2:
4824       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4825     case 3:
4826       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4827     default:
4828       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4829     }
4830     ierr = DMDestroy(dm);CHKERRQ(ierr);
4831     *dm  = idm;
4832   }
4833   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4834   PetscFunctionReturn(0);
4835 }
4836 
4837 #if defined(PETSC_HAVE_TRIANGLE)
4838 #include <triangle.h>
4839 
4840 #undef __FUNCT__
4841 #define __FUNCT__ "InitInput_Triangle"
4842 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4843 {
4844   PetscFunctionBegin;
4845   inputCtx->numberofpoints = 0;
4846   inputCtx->numberofpointattributes = 0;
4847   inputCtx->pointlist = PETSC_NULL;
4848   inputCtx->pointattributelist = PETSC_NULL;
4849   inputCtx->pointmarkerlist = PETSC_NULL;
4850   inputCtx->numberofsegments = 0;
4851   inputCtx->segmentlist = PETSC_NULL;
4852   inputCtx->segmentmarkerlist = PETSC_NULL;
4853   inputCtx->numberoftriangleattributes = 0;
4854   inputCtx->trianglelist = PETSC_NULL;
4855   inputCtx->numberofholes = 0;
4856   inputCtx->holelist = PETSC_NULL;
4857   inputCtx->numberofregions = 0;
4858   inputCtx->regionlist = PETSC_NULL;
4859   PetscFunctionReturn(0);
4860 }
4861 
4862 #undef __FUNCT__
4863 #define __FUNCT__ "InitOutput_Triangle"
4864 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4865 {
4866   PetscFunctionBegin;
4867   outputCtx->numberofpoints = 0;
4868   outputCtx->pointlist = PETSC_NULL;
4869   outputCtx->pointattributelist = PETSC_NULL;
4870   outputCtx->pointmarkerlist = PETSC_NULL;
4871   outputCtx->numberoftriangles = 0;
4872   outputCtx->trianglelist = PETSC_NULL;
4873   outputCtx->triangleattributelist = PETSC_NULL;
4874   outputCtx->neighborlist = PETSC_NULL;
4875   outputCtx->segmentlist = PETSC_NULL;
4876   outputCtx->segmentmarkerlist = PETSC_NULL;
4877   outputCtx->numberofedges = 0;
4878   outputCtx->edgelist = PETSC_NULL;
4879   outputCtx->edgemarkerlist = PETSC_NULL;
4880   PetscFunctionReturn(0);
4881 }
4882 
4883 #undef __FUNCT__
4884 #define __FUNCT__ "FiniOutput_Triangle"
4885 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4886 {
4887   PetscFunctionBegin;
4888   free(outputCtx->pointmarkerlist);
4889   free(outputCtx->edgelist);
4890   free(outputCtx->edgemarkerlist);
4891   free(outputCtx->trianglelist);
4892   free(outputCtx->neighborlist);
4893   PetscFunctionReturn(0);
4894 }
4895 
4896 #undef __FUNCT__
4897 #define __FUNCT__ "DMPlexGenerate_Triangle"
4898 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4899 {
4900   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4901   PetscInt             dim              = 2;
4902   const PetscBool      createConvexHull = PETSC_FALSE;
4903   const PetscBool      constrained      = PETSC_FALSE;
4904   struct triangulateio in;
4905   struct triangulateio out;
4906   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4907   PetscMPIInt          rank;
4908   PetscErrorCode       ierr;
4909 
4910   PetscFunctionBegin;
4911   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4912   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4913   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4914   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4915   in.numberofpoints = vEnd - vStart;
4916   if (in.numberofpoints > 0) {
4917     PetscSection coordSection;
4918     Vec          coordinates;
4919     PetscScalar *array;
4920 
4921     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4922     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4923     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4924     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4925     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4926     for (v = vStart; v < vEnd; ++v) {
4927       const PetscInt idx = v - vStart;
4928       PetscInt       off, d;
4929 
4930       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4931       for (d = 0; d < dim; ++d) {
4932         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4933       }
4934       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4935     }
4936     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4937   }
4938   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4939   in.numberofsegments = eEnd - eStart;
4940   if (in.numberofsegments > 0) {
4941     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4942     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4943     for (e = eStart; e < eEnd; ++e) {
4944       const PetscInt  idx = e - eStart;
4945       const PetscInt *cone;
4946 
4947       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4948       in.segmentlist[idx*2+0] = cone[0] - vStart;
4949       in.segmentlist[idx*2+1] = cone[1] - vStart;
4950       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4951     }
4952   }
4953 #if 0 /* Do not currently support holes */
4954   PetscReal *holeCoords;
4955   PetscInt   h, d;
4956 
4957   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4958   if (in.numberofholes > 0) {
4959     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4960     for (h = 0; h < in.numberofholes; ++h) {
4961       for (d = 0; d < dim; ++d) {
4962         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4963       }
4964     }
4965   }
4966 #endif
4967   if (!rank) {
4968     char args[32];
4969 
4970     /* Take away 'Q' for verbose output */
4971     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4972     if (createConvexHull) {
4973       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4974     }
4975     if (constrained) {
4976       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4977     }
4978     triangulate(args, &in, &out, PETSC_NULL);
4979   }
4980   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4981   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4982   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4983   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4984   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4985 
4986   {
4987     const PetscInt numCorners  = 3;
4988     const PetscInt numCells    = out.numberoftriangles;
4989     const PetscInt numVertices = out.numberofpoints;
4990     const int     *cells       = out.trianglelist;
4991     const double  *meshCoords  = out.pointlist;
4992 
4993     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4994     /* Set labels */
4995     for (v = 0; v < numVertices; ++v) {
4996       if (out.pointmarkerlist[v]) {
4997         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4998       }
4999     }
5000     if (interpolate) {
5001       for (e = 0; e < out.numberofedges; e++) {
5002         if (out.edgemarkerlist[e]) {
5003           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5004           const PetscInt *edges;
5005           PetscInt        numEdges;
5006 
5007           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5008           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5009           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5010           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5011         }
5012       }
5013     }
5014     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5015   }
5016 #if 0 /* Do not currently support holes */
5017   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5018 #endif
5019   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5020   PetscFunctionReturn(0);
5021 }
5022 
5023 #undef __FUNCT__
5024 #define __FUNCT__ "DMPlexRefine_Triangle"
5025 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5026 {
5027   MPI_Comm             comm = ((PetscObject) dm)->comm;
5028   PetscInt             dim  = 2;
5029   struct triangulateio in;
5030   struct triangulateio out;
5031   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5032   PetscMPIInt          rank;
5033   PetscErrorCode       ierr;
5034 
5035   PetscFunctionBegin;
5036   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5037   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5038   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5039   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5040   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5041   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5042   in.numberofpoints = vEnd - vStart;
5043   if (in.numberofpoints > 0) {
5044     PetscSection coordSection;
5045     Vec          coordinates;
5046     PetscScalar *array;
5047 
5048     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5049     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5050     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5051     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5052     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5053     for (v = vStart; v < vEnd; ++v) {
5054       const PetscInt idx = v - vStart;
5055       PetscInt       off, d;
5056 
5057       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5058       for (d = 0; d < dim; ++d) {
5059         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5060       }
5061       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5062     }
5063     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5064   }
5065   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5066   in.numberofcorners   = 3;
5067   in.numberoftriangles = cEnd - cStart;
5068   in.trianglearealist  = (double *) maxVolumes;
5069   if (in.numberoftriangles > 0) {
5070     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5071     for (c = cStart; c < cEnd; ++c) {
5072       const PetscInt idx     = c - cStart;
5073       PetscInt      *closure = PETSC_NULL;
5074       PetscInt       closureSize;
5075 
5076       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5077       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5078       for (v = 0; v < 3; ++v) {
5079         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5080       }
5081       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5082     }
5083   }
5084   /* TODO: Segment markers are missing on input */
5085 #if 0 /* Do not currently support holes */
5086   PetscReal *holeCoords;
5087   PetscInt   h, d;
5088 
5089   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5090   if (in.numberofholes > 0) {
5091     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5092     for (h = 0; h < in.numberofholes; ++h) {
5093       for (d = 0; d < dim; ++d) {
5094         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5095       }
5096     }
5097   }
5098 #endif
5099   if (!rank) {
5100     char args[32];
5101 
5102     /* Take away 'Q' for verbose output */
5103     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5104     triangulate(args, &in, &out, PETSC_NULL);
5105   }
5106   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5107   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5108   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5109   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5110   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5111 
5112   {
5113     const PetscInt numCorners  = 3;
5114     const PetscInt numCells    = out.numberoftriangles;
5115     const PetscInt numVertices = out.numberofpoints;
5116     const int     *cells       = out.trianglelist;
5117     const double  *meshCoords  = out.pointlist;
5118     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5119 
5120     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5121     /* Set labels */
5122     for (v = 0; v < numVertices; ++v) {
5123       if (out.pointmarkerlist[v]) {
5124         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5125       }
5126     }
5127     if (interpolate) {
5128       PetscInt e;
5129 
5130       for (e = 0; e < out.numberofedges; e++) {
5131         if (out.edgemarkerlist[e]) {
5132           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5133           const PetscInt *edges;
5134           PetscInt        numEdges;
5135 
5136           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5137           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5138           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5139           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5140         }
5141       }
5142     }
5143     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5144   }
5145 #if 0 /* Do not currently support holes */
5146   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5147 #endif
5148   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5149   PetscFunctionReturn(0);
5150 }
5151 #endif
5152 
5153 #if defined(PETSC_HAVE_TETGEN)
5154 #include <tetgen.h>
5155 #undef __FUNCT__
5156 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5157 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5158 {
5159   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5160   const PetscInt dim  = 3;
5161   ::tetgenio     in;
5162   ::tetgenio     out;
5163   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5164   PetscMPIInt    rank;
5165   PetscErrorCode ierr;
5166 
5167   PetscFunctionBegin;
5168   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5169   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5170   in.numberofpoints = vEnd - vStart;
5171   if (in.numberofpoints > 0) {
5172     PetscSection coordSection;
5173     Vec          coordinates;
5174     PetscScalar *array;
5175 
5176     in.pointlist       = new double[in.numberofpoints*dim];
5177     in.pointmarkerlist = new int[in.numberofpoints];
5178     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5179     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5180     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5181     for (v = vStart; v < vEnd; ++v) {
5182       const PetscInt idx = v - vStart;
5183       PetscInt       off, d;
5184 
5185       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5186       for (d = 0; d < dim; ++d) {
5187         in.pointlist[idx*dim + d] = array[off+d];
5188       }
5189       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5190     }
5191     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5192   }
5193   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5194   in.numberoffacets = fEnd - fStart;
5195   if (in.numberoffacets > 0) {
5196     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5197     in.facetmarkerlist = new int[in.numberoffacets];
5198     for (f = fStart; f < fEnd; ++f) {
5199       const PetscInt idx    = f - fStart;
5200       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5201 
5202       in.facetlist[idx].numberofpolygons = 1;
5203       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5204       in.facetlist[idx].numberofholes    = 0;
5205       in.facetlist[idx].holelist         = NULL;
5206 
5207       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5208       for (p = 0; p < numPoints*2; p += 2) {
5209         const PetscInt point = points[p];
5210         if ((point >= vStart) && (point < vEnd)) {
5211           points[numVertices++] = point;
5212         }
5213       }
5214 
5215       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5216       poly->numberofvertices = numVertices;
5217       poly->vertexlist       = new int[poly->numberofvertices];
5218       for (v = 0; v < numVertices; ++v) {
5219         const PetscInt vIdx = points[v] - vStart;
5220         poly->vertexlist[v] = vIdx;
5221       }
5222       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5223       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5224     }
5225   }
5226   if (!rank) {
5227     char args[32];
5228 
5229     /* Take away 'Q' for verbose output */
5230     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5231     ::tetrahedralize(args, &in, &out);
5232   }
5233   {
5234     const PetscInt numCorners  = 4;
5235     const PetscInt numCells    = out.numberoftetrahedra;
5236     const PetscInt numVertices = out.numberofpoints;
5237     const int     *cells       = out.tetrahedronlist;
5238     const double  *meshCoords  = out.pointlist;
5239 
5240     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5241     /* Set labels */
5242     for (v = 0; v < numVertices; ++v) {
5243       if (out.pointmarkerlist[v]) {
5244         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5245       }
5246     }
5247     if (interpolate) {
5248       PetscInt e;
5249 
5250       for (e = 0; e < out.numberofedges; e++) {
5251         if (out.edgemarkerlist[e]) {
5252           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5253           const PetscInt *edges;
5254           PetscInt        numEdges;
5255 
5256           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5257           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5258           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5259           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5260         }
5261       }
5262       for (f = 0; f < out.numberoftrifaces; f++) {
5263         if (out.trifacemarkerlist[f]) {
5264           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5265           const PetscInt *faces;
5266           PetscInt        numFaces;
5267 
5268           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5269           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5270           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5271           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5272         }
5273       }
5274     }
5275     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5276   }
5277   PetscFunctionReturn(0);
5278 }
5279 
5280 #undef __FUNCT__
5281 #define __FUNCT__ "DMPlexRefine_Tetgen"
5282 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5283 {
5284   MPI_Comm       comm = ((PetscObject) dm)->comm;
5285   const PetscInt dim  = 3;
5286   ::tetgenio     in;
5287   ::tetgenio     out;
5288   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5289   PetscMPIInt    rank;
5290   PetscErrorCode ierr;
5291 
5292   PetscFunctionBegin;
5293   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5294   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5295   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5296   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5297   in.numberofpoints = vEnd - vStart;
5298   if (in.numberofpoints > 0) {
5299     PetscSection coordSection;
5300     Vec          coordinates;
5301     PetscScalar *array;
5302 
5303     in.pointlist       = new double[in.numberofpoints*dim];
5304     in.pointmarkerlist = new int[in.numberofpoints];
5305     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5306     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5307     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5308     for (v = vStart; v < vEnd; ++v) {
5309       const PetscInt idx = v - vStart;
5310       PetscInt       off, d;
5311 
5312       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5313       for (d = 0; d < dim; ++d) {
5314         in.pointlist[idx*dim + d] = array[off+d];
5315       }
5316       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5317     }
5318     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5319   }
5320   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5321   in.numberofcorners       = 4;
5322   in.numberoftetrahedra    = cEnd - cStart;
5323   in.tetrahedronvolumelist = (double *) maxVolumes;
5324   if (in.numberoftetrahedra > 0) {
5325     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5326     for (c = cStart; c < cEnd; ++c) {
5327       const PetscInt idx     = c - cStart;
5328       PetscInt      *closure = PETSC_NULL;
5329       PetscInt       closureSize;
5330 
5331       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5332       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5333       for (v = 0; v < 4; ++v) {
5334         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5335       }
5336       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5337     }
5338   }
5339   /* TODO: Put in boundary faces with markers */
5340   if (!rank) {
5341     char args[32];
5342 
5343     /* Take away 'Q' for verbose output */
5344     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5345     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5346     ::tetrahedralize(args, &in, &out);
5347   }
5348   in.tetrahedronvolumelist = NULL;
5349 
5350   {
5351     const PetscInt numCorners  = 4;
5352     const PetscInt numCells    = out.numberoftetrahedra;
5353     const PetscInt numVertices = out.numberofpoints;
5354     const int     *cells       = out.tetrahedronlist;
5355     const double  *meshCoords  = out.pointlist;
5356     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5357 
5358     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5359     /* Set labels */
5360     for (v = 0; v < numVertices; ++v) {
5361       if (out.pointmarkerlist[v]) {
5362         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5363       }
5364     }
5365     if (interpolate) {
5366       PetscInt e, f;
5367 
5368       for (e = 0; e < out.numberofedges; e++) {
5369         if (out.edgemarkerlist[e]) {
5370           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5371           const PetscInt *edges;
5372           PetscInt        numEdges;
5373 
5374           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5375           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5376           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5377           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5378         }
5379       }
5380       for (f = 0; f < out.numberoftrifaces; f++) {
5381         if (out.trifacemarkerlist[f]) {
5382           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5383           const PetscInt *faces;
5384           PetscInt        numFaces;
5385 
5386           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5387           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5388           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5389           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5390         }
5391       }
5392     }
5393     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5394   }
5395   PetscFunctionReturn(0);
5396 }
5397 #endif
5398 
5399 #if defined(PETSC_HAVE_CTETGEN)
5400 #include "ctetgen.h"
5401 
5402 #undef __FUNCT__
5403 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5404 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5405 {
5406   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5407   const PetscInt dim  = 3;
5408   PLC           *in, *out;
5409   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5410   PetscMPIInt    rank;
5411   PetscErrorCode ierr;
5412 
5413   PetscFunctionBegin;
5414   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5415   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5416   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5417   ierr = PLCCreate(&in);CHKERRQ(ierr);
5418   ierr = PLCCreate(&out);CHKERRQ(ierr);
5419   in->numberofpoints = vEnd - vStart;
5420   if (in->numberofpoints > 0) {
5421     PetscSection coordSection;
5422     Vec          coordinates;
5423     PetscScalar *array;
5424 
5425     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5426     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5427     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5428     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5429     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5430     for (v = vStart; v < vEnd; ++v) {
5431       const PetscInt idx = v - vStart;
5432       PetscInt       off, d, m;
5433 
5434       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5435       for (d = 0; d < dim; ++d) {
5436         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5437       }
5438       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5439       in->pointmarkerlist[idx] = (int) m;
5440     }
5441     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5442   }
5443   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5444   in->numberoffacets = fEnd - fStart;
5445   if (in->numberoffacets > 0) {
5446     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5447     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5448     for (f = fStart; f < fEnd; ++f) {
5449       const PetscInt idx    = f - fStart;
5450       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5451       polygon       *poly;
5452 
5453       in->facetlist[idx].numberofpolygons = 1;
5454       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5455       in->facetlist[idx].numberofholes    = 0;
5456       in->facetlist[idx].holelist         = PETSC_NULL;
5457 
5458       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5459       for (p = 0; p < numPoints*2; p += 2) {
5460         const PetscInt point = points[p];
5461         if ((point >= vStart) && (point < vEnd)) {
5462           points[numVertices++] = point;
5463         }
5464       }
5465 
5466       poly = in->facetlist[idx].polygonlist;
5467       poly->numberofvertices = numVertices;
5468       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5469       for (v = 0; v < numVertices; ++v) {
5470         const PetscInt vIdx = points[v] - vStart;
5471         poly->vertexlist[v] = vIdx;
5472       }
5473       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5474       in->facetmarkerlist[idx] = (int) m;
5475       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5476     }
5477   }
5478   if (!rank) {
5479     TetGenOpts t;
5480 
5481     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5482     t.in        = boundary; /* Should go away */
5483     t.plc       = 1;
5484     t.quality   = 1;
5485     t.edgesout  = 1;
5486     t.zeroindex = 1;
5487     t.quiet     = 1;
5488     t.verbose   = verbose;
5489     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5490     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5491   }
5492   {
5493     const PetscInt numCorners  = 4;
5494     const PetscInt numCells    = out->numberoftetrahedra;
5495     const PetscInt numVertices = out->numberofpoints;
5496     const int     *cells       = out->tetrahedronlist;
5497     const double  *meshCoords  = out->pointlist;
5498 
5499     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5500     /* Set labels */
5501     for (v = 0; v < numVertices; ++v) {
5502       if (out->pointmarkerlist[v]) {
5503         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5504       }
5505     }
5506     if (interpolate) {
5507       PetscInt e;
5508 
5509       for (e = 0; e < out->numberofedges; e++) {
5510         if (out->edgemarkerlist[e]) {
5511           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5512           const PetscInt *edges;
5513           PetscInt        numEdges;
5514 
5515           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5516           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5517           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5518           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5519         }
5520       }
5521       for (f = 0; f < out->numberoftrifaces; f++) {
5522         if (out->trifacemarkerlist[f]) {
5523           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5524           const PetscInt *faces;
5525           PetscInt        numFaces;
5526 
5527           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5528           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5529           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5530           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5531         }
5532       }
5533     }
5534     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5535   }
5536 
5537   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5538   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5539   PetscFunctionReturn(0);
5540 }
5541 
5542 #undef __FUNCT__
5543 #define __FUNCT__ "DMPlexRefine_CTetgen"
5544 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5545 {
5546   MPI_Comm       comm = ((PetscObject) dm)->comm;
5547   const PetscInt dim  = 3;
5548   PLC           *in, *out;
5549   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5550   PetscMPIInt    rank;
5551   PetscErrorCode ierr;
5552 
5553   PetscFunctionBegin;
5554   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5555   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5556   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5557   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5558   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5559   ierr = PLCCreate(&in);CHKERRQ(ierr);
5560   ierr = PLCCreate(&out);CHKERRQ(ierr);
5561   in->numberofpoints = vEnd - vStart;
5562   if (in->numberofpoints > 0) {
5563     PetscSection coordSection;
5564     Vec          coordinates;
5565     PetscScalar *array;
5566 
5567     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5568     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5569     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5570     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5571     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5572     for (v = vStart; v < vEnd; ++v) {
5573       const PetscInt idx = v - vStart;
5574       PetscInt       off, d, m;
5575 
5576       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5577       for (d = 0; d < dim; ++d) {
5578         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5579       }
5580       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5581       in->pointmarkerlist[idx] = (int) m;
5582     }
5583     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5584   }
5585   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5586   in->numberofcorners       = 4;
5587   in->numberoftetrahedra    = cEnd - cStart;
5588   in->tetrahedronvolumelist = maxVolumes;
5589   if (in->numberoftetrahedra > 0) {
5590     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5591     for (c = cStart; c < cEnd; ++c) {
5592       const PetscInt idx     = c - cStart;
5593       PetscInt      *closure = PETSC_NULL;
5594       PetscInt       closureSize;
5595 
5596       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5597       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5598       for (v = 0; v < 4; ++v) {
5599         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5600       }
5601       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5602     }
5603   }
5604   if (!rank) {
5605     TetGenOpts t;
5606 
5607     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5608     t.in        = dm; /* Should go away */
5609     t.refine    = 1;
5610     t.varvolume = 1;
5611     t.quality   = 1;
5612     t.edgesout  = 1;
5613     t.zeroindex = 1;
5614     t.quiet     = 1;
5615     t.verbose   = verbose; /* Change this */
5616     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5617     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5618   }
5619   {
5620     const PetscInt numCorners  = 4;
5621     const PetscInt numCells    = out->numberoftetrahedra;
5622     const PetscInt numVertices = out->numberofpoints;
5623     const int     *cells       = out->tetrahedronlist;
5624     const double  *meshCoords  = out->pointlist;
5625     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5626 
5627     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5628     /* Set labels */
5629     for (v = 0; v < numVertices; ++v) {
5630       if (out->pointmarkerlist[v]) {
5631         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5632       }
5633     }
5634     if (interpolate) {
5635       PetscInt e, f;
5636 
5637       for (e = 0; e < out->numberofedges; e++) {
5638         if (out->edgemarkerlist[e]) {
5639           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5640           const PetscInt *edges;
5641           PetscInt        numEdges;
5642 
5643           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5644           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5645           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5646           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5647         }
5648       }
5649       for (f = 0; f < out->numberoftrifaces; f++) {
5650         if (out->trifacemarkerlist[f]) {
5651           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5652           const PetscInt *faces;
5653           PetscInt        numFaces;
5654 
5655           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5656           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5657           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5658           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5659         }
5660       }
5661     }
5662     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5663   }
5664   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5665   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5666   PetscFunctionReturn(0);
5667 }
5668 #endif
5669 
5670 #undef __FUNCT__
5671 #define __FUNCT__ "DMPlexGenerate"
5672 /*@C
5673   DMPlexGenerate - Generates a mesh.
5674 
5675   Not Collective
5676 
5677   Input Parameters:
5678 + boundary - The DMPlex boundary object
5679 . name - The mesh generation package name
5680 - interpolate - Flag to create intermediate mesh elements
5681 
5682   Output Parameter:
5683 . mesh - The DMPlex object
5684 
5685   Level: intermediate
5686 
5687 .keywords: mesh, elements
5688 .seealso: DMPlexCreate(), DMRefine()
5689 @*/
5690 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5691 {
5692   PetscInt       dim;
5693   char           genname[1024];
5694   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5695   PetscErrorCode ierr;
5696 
5697   PetscFunctionBegin;
5698   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5699   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5700   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5701   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5702   if (flg) {name = genname;}
5703   if (name) {
5704     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5705     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5706     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5707   }
5708   switch (dim) {
5709   case 1:
5710     if (!name || isTriangle) {
5711 #if defined(PETSC_HAVE_TRIANGLE)
5712       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5713 #else
5714       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5715 #endif
5716     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5717     break;
5718   case 2:
5719     if (!name || isCTetgen) {
5720 #if defined(PETSC_HAVE_CTETGEN)
5721       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5722 #else
5723       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5724 #endif
5725     } else if (isTetgen) {
5726 #if defined(PETSC_HAVE_TETGEN)
5727       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5728 #else
5729       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5730 #endif
5731     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5732     break;
5733   default:
5734     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5735   }
5736   PetscFunctionReturn(0);
5737 }
5738 
5739 typedef PetscInt CellRefiner;
5740 
5741 #undef __FUNCT__
5742 #define __FUNCT__ "GetDepthStart_Private"
5743 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5744 {
5745   PetscFunctionBegin;
5746   if (cStart) *cStart = 0;
5747   if (vStart) *vStart = depthSize[depth];
5748   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5749   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5750   PetscFunctionReturn(0);
5751 }
5752 
5753 #undef __FUNCT__
5754 #define __FUNCT__ "GetDepthEnd_Private"
5755 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5756 {
5757   PetscFunctionBegin;
5758   if (cEnd) *cEnd = depthSize[depth];
5759   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5760   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5761   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5762   PetscFunctionReturn(0);
5763 }
5764 
5765 #undef __FUNCT__
5766 #define __FUNCT__ "CellRefinerGetSizes"
5767 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5768 {
5769   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5770   PetscErrorCode ierr;
5771 
5772   PetscFunctionBegin;
5773   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5774   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5775   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5776   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5777   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5778   switch (refiner) {
5779   case 1:
5780     /* Simplicial 2D */
5781     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5782     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5783     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5784     break;
5785   case 3:
5786     /* Hybrid 2D */
5787     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5788     cMax = PetscMin(cEnd, cMax);
5789     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5790     fMax = PetscMin(fEnd, fMax);
5791     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5792     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 */
5793     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5794     break;
5795   case 2:
5796     /* Hex 2D */
5797     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5798     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5799     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5800     break;
5801   default:
5802     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5803   }
5804   PetscFunctionReturn(0);
5805 }
5806 
5807 #undef __FUNCT__
5808 #define __FUNCT__ "CellRefinerSetConeSizes"
5809 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5810 {
5811   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5812   PetscErrorCode ierr;
5813 
5814   PetscFunctionBegin;
5815   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5816   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5817   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5818   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5819   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5820   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5821   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5822   switch (refiner) {
5823   case 1:
5824     /* Simplicial 2D */
5825     /* All cells have 3 faces */
5826     for (c = cStart; c < cEnd; ++c) {
5827       for (r = 0; r < 4; ++r) {
5828         const PetscInt newp = (c - cStart)*4 + r;
5829 
5830         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5831       }
5832     }
5833     /* Split faces have 2 vertices and the same cells as the parent */
5834     for (f = fStart; f < fEnd; ++f) {
5835       for (r = 0; r < 2; ++r) {
5836         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5837         PetscInt       size;
5838 
5839         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5840         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5841         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5842       }
5843     }
5844     /* Interior faces have 2 vertices and 2 cells */
5845     for (c = cStart; c < cEnd; ++c) {
5846       for (r = 0; r < 3; ++r) {
5847         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5848 
5849         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5850         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5851       }
5852     }
5853     /* Old vertices have identical supports */
5854     for (v = vStart; v < vEnd; ++v) {
5855       const PetscInt newp = vStartNew + (v - vStart);
5856       PetscInt       size;
5857 
5858       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5859       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5860     }
5861     /* Face vertices have 2 + cells*2 supports */
5862     for (f = fStart; f < fEnd; ++f) {
5863       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5864       PetscInt       size;
5865 
5866       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5867       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5868     }
5869     break;
5870   case 2:
5871     /* Hex 2D */
5872     /* All cells have 4 faces */
5873     for (c = cStart; c < cEnd; ++c) {
5874       for (r = 0; r < 4; ++r) {
5875         const PetscInt newp = (c - cStart)*4 + r;
5876 
5877         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5878       }
5879     }
5880     /* Split faces have 2 vertices and the same cells as the parent */
5881     for (f = fStart; f < fEnd; ++f) {
5882       for (r = 0; r < 2; ++r) {
5883         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5884         PetscInt       size;
5885 
5886         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5887         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5888         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5889       }
5890     }
5891     /* Interior faces have 2 vertices and 2 cells */
5892     for (c = cStart; c < cEnd; ++c) {
5893       for (r = 0; r < 4; ++r) {
5894         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5895 
5896         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5897         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5898       }
5899     }
5900     /* Old vertices have identical supports */
5901     for (v = vStart; v < vEnd; ++v) {
5902       const PetscInt newp = vStartNew + (v - vStart);
5903       PetscInt       size;
5904 
5905       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5906       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5907     }
5908     /* Face vertices have 2 + cells supports */
5909     for (f = fStart; f < fEnd; ++f) {
5910       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5911       PetscInt       size;
5912 
5913       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5914       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5915     }
5916     /* Cell vertices have 4 supports */
5917     for (c = cStart; c < cEnd; ++c) {
5918       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5919 
5920       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5921     }
5922     break;
5923   case 3:
5924     /* Hybrid 2D */
5925     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5926     cMax = PetscMin(cEnd, cMax);
5927     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5928     fMax = PetscMin(fEnd, fMax);
5929     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5930     /* Interior cells have 3 faces */
5931     for (c = cStart; c < cMax; ++c) {
5932       for (r = 0; r < 4; ++r) {
5933         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5934 
5935         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5936       }
5937     }
5938     /* Hybrid cells have 4 faces */
5939     for (c = cMax; c < cEnd; ++c) {
5940       for (r = 0; r < 2; ++r) {
5941         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5942 
5943         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5944       }
5945     }
5946     /* Interior split faces have 2 vertices and the same cells as the parent */
5947     for (f = fStart; f < fMax; ++f) {
5948       for (r = 0; r < 2; ++r) {
5949         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5950         PetscInt       size;
5951 
5952         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5953         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5954         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5955       }
5956     }
5957     /* Interior cell faces have 2 vertices and 2 cells */
5958     for (c = cStart; c < cMax; ++c) {
5959       for (r = 0; r < 3; ++r) {
5960         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
5961 
5962         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5963         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5964       }
5965     }
5966     /* Hybrid faces have 2 vertices and the same cells */
5967     for (f = fMax; f < fEnd; ++f) {
5968       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
5969       PetscInt       size;
5970 
5971       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5972       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5973       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5974     }
5975     /* Hybrid cell faces have 2 vertices and 2 cells */
5976     for (c = cMax; c < cEnd; ++c) {
5977       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
5978 
5979       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5980       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5981     }
5982     /* Old vertices have identical supports */
5983     for (v = vStart; v < vEnd; ++v) {
5984       const PetscInt newp = vStartNew + (v - vStart);
5985       PetscInt       size;
5986 
5987       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5988       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5989     }
5990     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
5991     for (f = fStart; f < fMax; ++f) {
5992       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5993       const PetscInt *support;
5994       PetscInt        size, newSize = 2, s;
5995 
5996       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5997       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5998       for (s = 0; s < size; ++s) {
5999         if (support[s] >= cMax) {
6000           newSize += 1;
6001         } else {
6002           newSize += 2;
6003         }
6004       }
6005       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6006     }
6007     break;
6008   default:
6009     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6010   }
6011   PetscFunctionReturn(0);
6012 }
6013 
6014 #undef __FUNCT__
6015 #define __FUNCT__ "CellRefinerSetCones"
6016 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6017 {
6018   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;
6019   PetscInt       maxSupportSize, *supportRef;
6020   PetscErrorCode ierr;
6021 
6022   PetscFunctionBegin;
6023   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6024   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6025   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6026   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6027   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6028   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6029   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6030   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6031   switch (refiner) {
6032   case 1:
6033     /* Simplicial 2D */
6034     /*
6035      2
6036      |\
6037      | \
6038      |  \
6039      |   \
6040      | C  \
6041      |     \
6042      |      \
6043      2---1---1
6044      |\  D  / \
6045      | 2   0   \
6046      |A \ /  B  \
6047      0---0-------1
6048      */
6049     /* All cells have 3 faces */
6050     for (c = cStart; c < cEnd; ++c) {
6051       const PetscInt  newp = cStartNew + (c - cStart)*4;
6052       const PetscInt *cone, *ornt;
6053       PetscInt        coneNew[3], orntNew[3];
6054 
6055       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6056       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6057       /* A triangle */
6058       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6059       orntNew[0] = ornt[0];
6060       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6061       orntNew[1] = -2;
6062       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6063       orntNew[2] = ornt[2];
6064       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6065       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6066 #if 1
6067       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);
6068       for (p = 0; p < 3; ++p) {
6069         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);
6070       }
6071 #endif
6072       /* B triangle */
6073       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6074       orntNew[0] = ornt[0];
6075       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6076       orntNew[1] = ornt[1];
6077       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6078       orntNew[2] = -2;
6079       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6080       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6081 #if 1
6082       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);
6083       for (p = 0; p < 3; ++p) {
6084         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);
6085       }
6086 #endif
6087       /* C triangle */
6088       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6089       orntNew[0] = -2;
6090       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6091       orntNew[1] = ornt[1];
6092       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6093       orntNew[2] = ornt[2];
6094       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6095       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6096 #if 1
6097       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);
6098       for (p = 0; p < 3; ++p) {
6099         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);
6100       }
6101 #endif
6102       /* D triangle */
6103       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6104       orntNew[0] = 0;
6105       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6106       orntNew[1] = 0;
6107       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6108       orntNew[2] = 0;
6109       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6110       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6111 #if 1
6112       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);
6113       for (p = 0; p < 3; ++p) {
6114         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);
6115       }
6116 #endif
6117     }
6118     /* Split faces have 2 vertices and the same cells as the parent */
6119     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6120     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6121     for (f = fStart; f < fEnd; ++f) {
6122       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6123 
6124       for (r = 0; r < 2; ++r) {
6125         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6126         const PetscInt *cone, *support;
6127         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6128 
6129         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6130         coneNew[0] = vStartNew + (cone[0] - vStart);
6131         coneNew[1] = vStartNew + (cone[1] - vStart);
6132         coneNew[(r+1)%2] = newv;
6133         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6134 #if 1
6135         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6136         for (p = 0; p < 2; ++p) {
6137           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);
6138         }
6139 #endif
6140         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6141         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6142         for (s = 0; s < supportSize; ++s) {
6143           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6144           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6145           for (c = 0; c < coneSize; ++c) {
6146             if (cone[c] == f) {
6147               break;
6148             }
6149           }
6150           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6151         }
6152         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6153 #if 1
6154         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6155         for (p = 0; p < supportSize; ++p) {
6156           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);
6157         }
6158 #endif
6159       }
6160     }
6161     /* Interior faces have 2 vertices and 2 cells */
6162     for (c = cStart; c < cEnd; ++c) {
6163       const PetscInt *cone;
6164 
6165       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6166       for (r = 0; r < 3; ++r) {
6167         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6168         PetscInt       coneNew[2];
6169         PetscInt       supportNew[2];
6170 
6171         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6172         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6173         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6174 #if 1
6175         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6176         for (p = 0; p < 2; ++p) {
6177           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);
6178         }
6179 #endif
6180         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6181         supportNew[1] = (c - cStart)*4 + 3;
6182         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6183 #if 1
6184         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6185         for (p = 0; p < 2; ++p) {
6186           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);
6187         }
6188 #endif
6189       }
6190     }
6191     /* Old vertices have identical supports */
6192     for (v = vStart; v < vEnd; ++v) {
6193       const PetscInt  newp = vStartNew + (v - vStart);
6194       const PetscInt *support, *cone;
6195       PetscInt        size, s;
6196 
6197       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6198       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6199       for (s = 0; s < size; ++s) {
6200         PetscInt r = 0;
6201 
6202         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6203         if (cone[1] == v) r = 1;
6204         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6205       }
6206       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6207 #if 1
6208       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6209       for (p = 0; p < size; ++p) {
6210         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);
6211       }
6212 #endif
6213     }
6214     /* Face vertices have 2 + cells*2 supports */
6215     for (f = fStart; f < fEnd; ++f) {
6216       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6217       const PetscInt *cone, *support;
6218       PetscInt        size, s;
6219 
6220       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6221       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6222       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6223       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6224       for (s = 0; s < size; ++s) {
6225         PetscInt r = 0;
6226 
6227         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6228         if      (cone[1] == f) r = 1;
6229         else if (cone[2] == f) r = 2;
6230         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6231         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6232       }
6233       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6234 #if 1
6235       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6236       for (p = 0; p < 2+size*2; ++p) {
6237         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);
6238       }
6239 #endif
6240     }
6241     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6242     break;
6243   case 2:
6244     /* Hex 2D */
6245     /*
6246      3---------2---------2
6247      |         |         |
6248      |    D    2    C    |
6249      |         |         |
6250      3----3----0----1----1
6251      |         |         |
6252      |    A    0    B    |
6253      |         |         |
6254      0---------0---------1
6255      */
6256     /* All cells have 4 faces */
6257     for (c = cStart; c < cEnd; ++c) {
6258       const PetscInt  newp = (c - cStart)*4;
6259       const PetscInt *cone, *ornt;
6260       PetscInt        coneNew[4], orntNew[4];
6261 
6262       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6263       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6264       /* A quad */
6265       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6266       orntNew[0] = ornt[0];
6267       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6268       orntNew[1] = 0;
6269       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6270       orntNew[2] = -2;
6271       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6272       orntNew[3] = ornt[3];
6273       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6274       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6275 #if 1
6276       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);
6277       for (p = 0; p < 4; ++p) {
6278         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);
6279       }
6280 #endif
6281       /* B quad */
6282       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6283       orntNew[0] = ornt[0];
6284       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6285       orntNew[1] = ornt[1];
6286       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6287       orntNew[2] = 0;
6288       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6289       orntNew[3] = -2;
6290       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6291       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6292 #if 1
6293       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);
6294       for (p = 0; p < 4; ++p) {
6295         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);
6296       }
6297 #endif
6298       /* C quad */
6299       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6300       orntNew[0] = -2;
6301       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6302       orntNew[1] = ornt[1];
6303       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6304       orntNew[2] = ornt[2];
6305       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6306       orntNew[3] = 0;
6307       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6308       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6309 #if 1
6310       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);
6311       for (p = 0; p < 4; ++p) {
6312         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);
6313       }
6314 #endif
6315       /* D quad */
6316       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6317       orntNew[0] = 0;
6318       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6319       orntNew[1] = -2;
6320       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6321       orntNew[2] = ornt[2];
6322       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6323       orntNew[3] = ornt[3];
6324       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6325       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6326 #if 1
6327       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);
6328       for (p = 0; p < 4; ++p) {
6329         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);
6330       }
6331 #endif
6332     }
6333     /* Split faces have 2 vertices and the same cells as the parent */
6334     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6335     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6336     for (f = fStart; f < fEnd; ++f) {
6337       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6338 
6339       for (r = 0; r < 2; ++r) {
6340         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6341         const PetscInt *cone, *support;
6342         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6343 
6344         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6345         coneNew[0] = vStartNew + (cone[0] - vStart);
6346         coneNew[1] = vStartNew + (cone[1] - vStart);
6347         coneNew[(r+1)%2] = newv;
6348         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6349 #if 1
6350         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6351         for (p = 0; p < 2; ++p) {
6352           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);
6353         }
6354 #endif
6355         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6356         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6357         for (s = 0; s < supportSize; ++s) {
6358           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6359           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6360           for (c = 0; c < coneSize; ++c) {
6361             if (cone[c] == f) {
6362               break;
6363             }
6364           }
6365           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6366         }
6367         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6368 #if 1
6369         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6370         for (p = 0; p < supportSize; ++p) {
6371           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);
6372         }
6373 #endif
6374       }
6375     }
6376     /* Interior faces have 2 vertices and 2 cells */
6377     for (c = cStart; c < cEnd; ++c) {
6378       const PetscInt *cone;
6379       PetscInt        coneNew[2], supportNew[2];
6380 
6381       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6382       for (r = 0; r < 4; ++r) {
6383         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6384 
6385         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6386         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6387         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6388 #if 1
6389         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6390         for (p = 0; p < 2; ++p) {
6391           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);
6392         }
6393 #endif
6394         supportNew[0] = (c - cStart)*4 + r;
6395         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6396         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6397 #if 1
6398         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6399         for (p = 0; p < 2; ++p) {
6400           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);
6401         }
6402 #endif
6403       }
6404     }
6405     /* Old vertices have identical supports */
6406     for (v = vStart; v < vEnd; ++v) {
6407       const PetscInt  newp = vStartNew + (v - vStart);
6408       const PetscInt *support, *cone;
6409       PetscInt        size, s;
6410 
6411       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6412       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6413       for (s = 0; s < size; ++s) {
6414         PetscInt r = 0;
6415 
6416         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6417         if (cone[1] == v) r = 1;
6418         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6419       }
6420       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6421 #if 1
6422       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6423       for (p = 0; p < size; ++p) {
6424         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);
6425       }
6426 #endif
6427     }
6428     /* Face vertices have 2 + cells supports */
6429     for (f = fStart; f < fEnd; ++f) {
6430       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6431       const PetscInt *cone, *support;
6432       PetscInt        size, s;
6433 
6434       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6435       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6436       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6437       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6438       for (s = 0; s < size; ++s) {
6439         PetscInt r = 0;
6440 
6441         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6442         if      (cone[1] == f) r = 1;
6443         else if (cone[2] == f) r = 2;
6444         else if (cone[3] == f) r = 3;
6445         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6446       }
6447       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6448 #if 1
6449       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6450       for (p = 0; p < 2+size; ++p) {
6451         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);
6452       }
6453 #endif
6454     }
6455     /* Cell vertices have 4 supports */
6456     for (c = cStart; c < cEnd; ++c) {
6457       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6458       PetscInt       supportNew[4];
6459 
6460       for (r = 0; r < 4; ++r) {
6461         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6462       }
6463       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6464     }
6465     break;
6466   case 3:
6467     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6468     cMax = PetscMin(cEnd, cMax);
6469     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6470     fMax = PetscMin(fEnd, fMax);
6471     /* Interior cells have 3 faces */
6472     for (c = cStart; c < cMax; ++c) {
6473       const PetscInt  newp = cStartNew + (c - cStart)*4;
6474       const PetscInt *cone, *ornt;
6475       PetscInt        coneNew[3], orntNew[3];
6476 
6477       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6478       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6479       /* A triangle */
6480       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6481       orntNew[0] = ornt[0];
6482       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6483       orntNew[1] = -2;
6484       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6485       orntNew[2] = ornt[2];
6486       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6487       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6488 #if 1
6489       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);
6490       for (p = 0; p < 3; ++p) {
6491         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);
6492       }
6493 #endif
6494       /* B triangle */
6495       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6496       orntNew[0] = ornt[0];
6497       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6498       orntNew[1] = ornt[1];
6499       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6500       orntNew[2] = -2;
6501       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6502       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6503 #if 1
6504       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);
6505       for (p = 0; p < 3; ++p) {
6506         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);
6507       }
6508 #endif
6509       /* C triangle */
6510       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6511       orntNew[0] = -2;
6512       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6513       orntNew[1] = ornt[1];
6514       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6515       orntNew[2] = ornt[2];
6516       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6517       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6518 #if 1
6519       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);
6520       for (p = 0; p < 3; ++p) {
6521         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);
6522       }
6523 #endif
6524       /* D triangle */
6525       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6526       orntNew[0] = 0;
6527       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6528       orntNew[1] = 0;
6529       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6530       orntNew[2] = 0;
6531       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6532       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6533 #if 1
6534       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);
6535       for (p = 0; p < 3; ++p) {
6536         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);
6537       }
6538 #endif
6539     }
6540     /*
6541      2----3----3
6542      |         |
6543      |    B    |
6544      |         |
6545      0----4--- 1
6546      |         |
6547      |    A    |
6548      |         |
6549      0----2----1
6550      */
6551     /* Hybrid cells have 4 faces */
6552     for (c = cMax; c < cEnd; ++c) {
6553       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6554       const PetscInt *cone, *ornt;
6555       PetscInt        coneNew[4], orntNew[4];
6556 
6557       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6558       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6559       /* A quad */
6560       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
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 + (cMax - cStart)*3 + (cone[2] - fMax);
6565       orntNew[2] = 0;
6566       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6567       orntNew[3] = 0;
6568       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6569       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6570 #if 1
6571       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);
6572       for (p = 0; p < 4; ++p) {
6573         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);
6574       }
6575 #endif
6576       /* B quad */
6577       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6578       orntNew[0] = ornt[0];
6579       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6580       orntNew[1] = ornt[1];
6581       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6582       orntNew[2] = 0;
6583       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6584       orntNew[3] = 0;
6585       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6586       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6587 #if 1
6588       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);
6589       for (p = 0; p < 4; ++p) {
6590         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);
6591       }
6592 #endif
6593     }
6594     /* Interior split faces have 2 vertices and the same cells as the parent */
6595     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6596     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6597     for (f = fStart; f < fMax; ++f) {
6598       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6599 
6600       for (r = 0; r < 2; ++r) {
6601         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6602         const PetscInt *cone, *support;
6603         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6604 
6605         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6606         coneNew[0] = vStartNew + (cone[0] - vStart);
6607         coneNew[1] = vStartNew + (cone[1] - vStart);
6608         coneNew[(r+1)%2] = newv;
6609         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6610 #if 1
6611         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6612         for (p = 0; p < 2; ++p) {
6613           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);
6614         }
6615 #endif
6616         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6617         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6618         for (s = 0; s < supportSize; ++s) {
6619           if (support[s] >= cMax) {
6620             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6621           } else {
6622             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6623             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6624             for (c = 0; c < coneSize; ++c) {
6625               if (cone[c] == f) {
6626                 break;
6627               }
6628             }
6629             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6630           }
6631         }
6632         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6633 #if 1
6634         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6635         for (p = 0; p < supportSize; ++p) {
6636           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);
6637         }
6638 #endif
6639       }
6640     }
6641     /* Interior cell faces have 2 vertices and 2 cells */
6642     for (c = cStart; c < cMax; ++c) {
6643       const PetscInt *cone;
6644 
6645       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6646       for (r = 0; r < 3; ++r) {
6647         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6648         PetscInt       coneNew[2];
6649         PetscInt       supportNew[2];
6650 
6651         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6652         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6653         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6654 #if 1
6655         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6656         for (p = 0; p < 2; ++p) {
6657           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);
6658         }
6659 #endif
6660         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6661         supportNew[1] = (c - cStart)*4 + 3;
6662         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6663 #if 1
6664         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6665         for (p = 0; p < 2; ++p) {
6666           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);
6667         }
6668 #endif
6669       }
6670     }
6671     /* Interior hybrid faces have 2 vertices and the same cells */
6672     for (f = fMax; f < fEnd; ++f) {
6673       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6674       const PetscInt *cone;
6675       const PetscInt *support;
6676       PetscInt        coneNew[2];
6677       PetscInt        supportNew[2];
6678       PetscInt        size, s, r;
6679 
6680       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6681       coneNew[0] = vStartNew + (cone[0] - vStart);
6682       coneNew[1] = vStartNew + (cone[1] - vStart);
6683       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6684 #if 1
6685       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6686       for (p = 0; p < 2; ++p) {
6687         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);
6688       }
6689 #endif
6690       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6691       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6692       for (s = 0; s < size; ++s) {
6693         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6694         for (r = 0; r < 2; ++r) {
6695           if (cone[r+2] == f) break;
6696         }
6697         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6698       }
6699       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6700 #if 1
6701       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6702       for (p = 0; p < size; ++p) {
6703         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);
6704       }
6705 #endif
6706     }
6707     /* Cell hybrid faces have 2 vertices and 2 cells */
6708     for (c = cMax; c < cEnd; ++c) {
6709       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6710       const PetscInt *cone;
6711       PetscInt        coneNew[2];
6712       PetscInt        supportNew[2];
6713 
6714       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6715       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6716       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6717       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6718 #if 1
6719       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6720       for (p = 0; p < 2; ++p) {
6721         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6722       }
6723 #endif
6724       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6725       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6726       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6727 #if 1
6728       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6729       for (p = 0; p < 2; ++p) {
6730         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6731       }
6732 #endif
6733     }
6734     /* Old vertices have identical supports */
6735     for (v = vStart; v < vEnd; ++v) {
6736       const PetscInt  newp = vStartNew + (v - vStart);
6737       const PetscInt *support, *cone;
6738       PetscInt        size, s;
6739 
6740       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6741       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6742       for (s = 0; s < size; ++s) {
6743         if (support[s] >= fMax) {
6744           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6745         } else {
6746           PetscInt r = 0;
6747 
6748           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6749           if (cone[1] == v) r = 1;
6750           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6751         }
6752       }
6753       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6754 #if 1
6755       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6756       for (p = 0; p < size; ++p) {
6757         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);
6758       }
6759 #endif
6760     }
6761     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6762     for (f = fStart; f < fMax; ++f) {
6763       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6764       const PetscInt *cone, *support;
6765       PetscInt        size, newSize = 2, s;
6766 
6767       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6768       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6769       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6770       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6771       for (s = 0; s < size; ++s) {
6772         PetscInt r = 0;
6773 
6774         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6775         if (support[s] >= cMax) {
6776           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6777           newSize += 1;
6778         } else {
6779           if      (cone[1] == f) r = 1;
6780           else if (cone[2] == f) r = 2;
6781           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6782           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6783           newSize += 2;
6784         }
6785       }
6786       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6787 #if 1
6788       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6789       for (p = 0; p < newSize; ++p) {
6790         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);
6791       }
6792 #endif
6793     }
6794     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6795     break;
6796   default:
6797     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6798   }
6799   PetscFunctionReturn(0);
6800 }
6801 
6802 #undef __FUNCT__
6803 #define __FUNCT__ "CellRefinerSetCoordinates"
6804 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6805 {
6806   PetscSection   coordSection, coordSectionNew;
6807   Vec            coordinates, coordinatesNew;
6808   PetscScalar   *coords, *coordsNew;
6809   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6810   PetscErrorCode ierr;
6811 
6812   PetscFunctionBegin;
6813   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6814   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6815   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6816   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6817   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6818   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6819   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6820   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6821   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6822   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6823   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6824   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6825   if (fMax < 0) fMax = fEnd;
6826   switch (refiner) {
6827   case 1:
6828   case 2:
6829   case 3:
6830     /* Simplicial and Hex 2D */
6831     /* All vertices have the dim coordinates */
6832     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6833       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6834       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6835     }
6836     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6837     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6838     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6839     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6840     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6841     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6842     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6843     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6844     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6845     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6846     /* Old vertices have the same coordinates */
6847     for (v = vStart; v < vEnd; ++v) {
6848       const PetscInt newv = vStartNew + (v - vStart);
6849       PetscInt       off, offnew, d;
6850 
6851       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6852       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6853       for (d = 0; d < dim; ++d) {
6854         coordsNew[offnew+d] = coords[off+d];
6855       }
6856     }
6857     /* Face vertices have the average of endpoint coordinates */
6858     for (f = fStart; f < fMax; ++f) {
6859       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6860       const PetscInt *cone;
6861       PetscInt        coneSize, offA, offB, offnew, d;
6862 
6863       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6864       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6865       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6866       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6867       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6868       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6869       for (d = 0; d < dim; ++d) {
6870         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6871       }
6872     }
6873     /* Just Hex 2D */
6874     if (refiner == 2) {
6875       /* Cell vertices have the average of corner coordinates */
6876       for (c = cStart; c < cEnd; ++c) {
6877         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6878         PetscInt      *cone = PETSC_NULL;
6879         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6880 
6881         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6882         for (p = 0; p < closureSize*2; p += 2) {
6883           const PetscInt point = cone[p];
6884           if ((point >= vStart) && (point < vEnd)) {
6885             cone[coneSize++] = point;
6886           }
6887         }
6888         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6889         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6890         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6891         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6892         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6893         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6894         for (d = 0; d < dim; ++d) {
6895           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6896         }
6897         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6898       }
6899     }
6900     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6901     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6902     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6903     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6904     break;
6905   default:
6906     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6907   }
6908   PetscFunctionReturn(0);
6909 }
6910 
6911 #undef __FUNCT__
6912 #define __FUNCT__ "DMPlexCreateProcessSF"
6913 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6914 {
6915   PetscInt           numRoots, numLeaves, l;
6916   const PetscInt    *localPoints;
6917   const PetscSFNode *remotePoints;
6918   PetscInt          *localPointsNew;
6919   PetscSFNode       *remotePointsNew;
6920   PetscInt          *ranks, *ranksNew;
6921   PetscErrorCode     ierr;
6922 
6923   PetscFunctionBegin;
6924   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6925   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6926   for (l = 0; l < numLeaves; ++l) {
6927     ranks[l] = remotePoints[l].rank;
6928   }
6929   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6930   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6931   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6932   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6933   for (l = 0; l < numLeaves; ++l) {
6934     ranksNew[l]              = ranks[l];
6935     localPointsNew[l]        = l;
6936     remotePointsNew[l].index = 0;
6937     remotePointsNew[l].rank  = ranksNew[l];
6938   }
6939   ierr = PetscFree(ranks);CHKERRQ(ierr);
6940   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6941   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6942   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6943   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6944   PetscFunctionReturn(0);
6945 }
6946 
6947 #undef __FUNCT__
6948 #define __FUNCT__ "CellRefinerCreateSF"
6949 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6950 {
6951   PetscSF            sf, sfNew, sfProcess;
6952   IS                 processRanks;
6953   MPI_Datatype       depthType;
6954   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6955   const PetscInt    *localPoints, *neighbors;
6956   const PetscSFNode *remotePoints;
6957   PetscInt          *localPointsNew;
6958   PetscSFNode       *remotePointsNew;
6959   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6960   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
6961   PetscErrorCode     ierr;
6962 
6963   PetscFunctionBegin;
6964   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6965   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6966   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6967   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6968   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6969   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6970   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6971   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6972   switch (refiner) {
6973   case 3:
6974     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6975     cMax = PetscMin(cEnd, cMax);
6976     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6977     fMax = PetscMin(fEnd, fMax);
6978   }
6979   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6980   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6981   /* Caculate size of new SF */
6982   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6983   if (numRoots < 0) PetscFunctionReturn(0);
6984   for (l = 0; l < numLeaves; ++l) {
6985     const PetscInt p = localPoints[l];
6986 
6987     switch (refiner) {
6988     case 1:
6989       /* Simplicial 2D */
6990       if ((p >= vStart) && (p < vEnd)) {
6991         /* Old vertices stay the same */
6992         ++numLeavesNew;
6993       } else if ((p >= fStart) && (p < fEnd)) {
6994         /* Old faces add new faces and vertex */
6995         numLeavesNew += 1 + 2;
6996       } else if ((p >= cStart) && (p < cEnd)) {
6997         /* Old cells add new cells and interior faces */
6998         numLeavesNew += 4 + 3;
6999       }
7000       break;
7001     case 2:
7002       /* Hex 2D */
7003       if ((p >= vStart) && (p < vEnd)) {
7004         /* Old vertices stay the same */
7005         ++numLeavesNew;
7006       } else if ((p >= fStart) && (p < fEnd)) {
7007         /* Old faces add new faces and vertex */
7008         numLeavesNew += 1 + 2;
7009       } else if ((p >= cStart) && (p < cEnd)) {
7010         /* Old cells add new cells and interior faces */
7011         numLeavesNew += 4 + 4;
7012       }
7013       break;
7014     default:
7015       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7016     }
7017   }
7018   /* Communicate depthSizes for each remote rank */
7019   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7020   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7021   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7022   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);
7023   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7024   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7025   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7026   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7027   for (n = 0; n < numNeighbors; ++n) {
7028     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7029   }
7030   depthSizeOld[depth]   = cMax;
7031   depthSizeOld[0]       = vMax;
7032   depthSizeOld[depth-1] = fMax;
7033   depthSizeOld[1]       = eMax;
7034   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7035   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7036   depthSizeOld[depth]   = cEnd - cStart;
7037   depthSizeOld[0]       = vEnd - vStart;
7038   depthSizeOld[depth-1] = fEnd - fStart;
7039   depthSizeOld[1]       = eEnd - eStart;
7040   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7041   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7042   for (n = 0; n < numNeighbors; ++n) {
7043     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7044   }
7045   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7046   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7047   /* Calculate new point SF */
7048   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7049   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7050   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7051   for (l = 0, m = 0; l < numLeaves; ++l) {
7052     PetscInt    p     = localPoints[l];
7053     PetscInt    rp    = remotePoints[l].index, n;
7054     PetscMPIInt rrank = remotePoints[l].rank;
7055 
7056     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7057     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7058     switch (refiner) {
7059     case 1:
7060       /* Simplicial 2D */
7061       if ((p >= vStart) && (p < vEnd)) {
7062         /* Old vertices stay the same */
7063         localPointsNew[m]        = vStartNew     + (p  - vStart);
7064         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7065         remotePointsNew[m].rank  = rrank;
7066         ++m;
7067       } else if ((p >= fStart) && (p < fEnd)) {
7068         /* Old faces add new faces and vertex */
7069         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7070         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7071         remotePointsNew[m].rank  = rrank;
7072         ++m;
7073         for (r = 0; r < 2; ++r, ++m) {
7074           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7075           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7076           remotePointsNew[m].rank  = rrank;
7077         }
7078       } else if ((p >= cStart) && (p < cEnd)) {
7079         /* Old cells add new cells and interior faces */
7080         for (r = 0; r < 4; ++r, ++m) {
7081           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7082           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7083           remotePointsNew[m].rank  = rrank;
7084         }
7085         for (r = 0; r < 3; ++r, ++m) {
7086           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7087           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7088           remotePointsNew[m].rank  = rrank;
7089         }
7090       }
7091       break;
7092     case 2:
7093       /* Hex 2D */
7094       if ((p >= vStart) && (p < vEnd)) {
7095         /* Old vertices stay the same */
7096         localPointsNew[m]        = vStartNew     + (p  - vStart);
7097         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7098         remotePointsNew[m].rank  = rrank;
7099         ++m;
7100       } else if ((p >= fStart) && (p < fEnd)) {
7101         /* Old faces add new faces and vertex */
7102         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7103         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7104         remotePointsNew[m].rank  = rrank;
7105         ++m;
7106         for (r = 0; r < 2; ++r, ++m) {
7107           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7108           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7109           remotePointsNew[m].rank  = rrank;
7110         }
7111       } else if ((p >= cStart) && (p < cEnd)) {
7112         /* Old cells add new cells and interior faces */
7113         for (r = 0; r < 4; ++r, ++m) {
7114           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7115           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7116           remotePointsNew[m].rank  = rrank;
7117         }
7118         for (r = 0; r < 4; ++r, ++m) {
7119           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7120           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7121           remotePointsNew[m].rank  = rrank;
7122         }
7123       }
7124       break;
7125     case 3:
7126       /* Hybrid 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 < fMax)) {
7134         /* Old interior 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 >= fMax) && (p < fEnd)) {
7145         /* Old hybrid faces stay the same */
7146         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7147         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7148         remotePointsNew[m].rank  = rrank;
7149         ++m;
7150       } else if ((p >= cStart) && (p < cMax)) {
7151         /* Old interior cells add new cells and interior faces */
7152         for (r = 0; r < 4; ++r, ++m) {
7153           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7154           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7155           remotePointsNew[m].rank  = rrank;
7156         }
7157         for (r = 0; r < 3; ++r, ++m) {
7158           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7159           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7160           remotePointsNew[m].rank  = rrank;
7161         }
7162       } else if ((p >= cStart) && (p < cMax)) {
7163         /* Old hybrid cells add new cells and hybrid face */
7164         for (r = 0; r < 2; ++r, ++m) {
7165           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7166           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7167           remotePointsNew[m].rank  = rrank;
7168         }
7169         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7170         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]);
7171         remotePointsNew[m].rank  = rrank;
7172         ++m;
7173       }
7174       break;
7175     default:
7176       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7177     }
7178   }
7179   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7180   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7181   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7182   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7183   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7184   PetscFunctionReturn(0);
7185 }
7186 
7187 #undef __FUNCT__
7188 #define __FUNCT__ "CellRefinerCreateLabels"
7189 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7190 {
7191   PetscInt       numLabels, l;
7192   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7193   PetscErrorCode ierr;
7194 
7195   PetscFunctionBegin;
7196   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7197   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7198   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7199   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7200   cStartNew = 0;
7201   vStartNew = depthSize[2];
7202   fStartNew = depthSize[2] + depthSize[0];
7203   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7204   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7205   switch (refiner) {
7206   case 3:
7207     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7208     cMax = PetscMin(cEnd, cMax);
7209     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7210     fMax = PetscMin(fEnd, fMax);
7211   }
7212   for (l = 0; l < numLabels; ++l) {
7213     DMLabel         label, labelNew;
7214     const char     *lname;
7215     PetscBool       isDepth;
7216     IS              valueIS;
7217     const PetscInt *values;
7218     PetscInt        numValues, val;
7219 
7220     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7221     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7222     if (isDepth) continue;
7223     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7224     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7225     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7226     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7227     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7228     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7229     for (val = 0; val < numValues; ++val) {
7230       IS              pointIS;
7231       const PetscInt *points;
7232       PetscInt        numPoints, n;
7233 
7234       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7235       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7236       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7237       for (n = 0; n < numPoints; ++n) {
7238         const PetscInt p = points[n];
7239         switch (refiner) {
7240         case 1:
7241           /* Simplicial 2D */
7242           if ((p >= vStart) && (p < vEnd)) {
7243             /* Old vertices stay the same */
7244             newp = vStartNew + (p - vStart);
7245             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7246           } else if ((p >= fStart) && (p < fEnd)) {
7247             /* Old faces add new faces and vertex */
7248             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7249             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7250             for (r = 0; r < 2; ++r) {
7251               newp = fStartNew + (p - fStart)*2 + r;
7252               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7253             }
7254           } else if ((p >= cStart) && (p < cEnd)) {
7255             /* Old cells add new cells and interior faces */
7256             for (r = 0; r < 4; ++r) {
7257               newp = cStartNew + (p - cStart)*4 + r;
7258               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7259             }
7260             for (r = 0; r < 3; ++r) {
7261               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7262               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7263             }
7264           }
7265           break;
7266         case 2:
7267           /* Hex 2D */
7268           if ((p >= vStart) && (p < vEnd)) {
7269             /* Old vertices stay the same */
7270             newp = vStartNew + (p - vStart);
7271             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7272           } else if ((p >= fStart) && (p < fEnd)) {
7273             /* Old faces add new faces and vertex */
7274             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7275             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7276             for (r = 0; r < 2; ++r) {
7277               newp = fStartNew + (p - fStart)*2 + r;
7278               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7279             }
7280           } else if ((p >= cStart) && (p < cEnd)) {
7281             /* Old cells add new cells and interior faces and vertex */
7282             for (r = 0; r < 4; ++r) {
7283               newp = cStartNew + (p - cStart)*4 + r;
7284               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7285             }
7286             for (r = 0; r < 4; ++r) {
7287               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7288               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7289             }
7290             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7291             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7292           }
7293           break;
7294         case 3:
7295           /* Hybrid simplicial 2D */
7296           if ((p >= vStart) && (p < vEnd)) {
7297             /* Old vertices stay the same */
7298             newp = vStartNew + (p - vStart);
7299             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7300           } else if ((p >= fStart) && (p < fMax)) {
7301             /* Old interior faces add new faces and vertex */
7302             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7303             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7304             for (r = 0; r < 2; ++r) {
7305               newp = fStartNew + (p - fStart)*2 + r;
7306               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7307             }
7308           } else if ((p >= fMax) && (p < fEnd)) {
7309             /* Old hybrid faces stay the same */
7310             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7311             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7312           } else if ((p >= cStart) && (p < cMax)) {
7313             /* Old interior cells add new cells and interior faces */
7314             for (r = 0; r < 4; ++r) {
7315               newp = cStartNew + (p - cStart)*4 + r;
7316               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7317             }
7318             for (r = 0; r < 3; ++r) {
7319               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7320               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7321             }
7322           } else if ((p >= cMax) && (p < cEnd)) {
7323             /* Old hybrid cells add new cells and hybrid face */
7324             for (r = 0; r < 2; ++r) {
7325               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7326               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7327             }
7328             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7329             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7330           }
7331           break;
7332         default:
7333           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7334         }
7335       }
7336       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7337       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7338     }
7339     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7340     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7341     if (0) {
7342       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7343       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7344       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7345     }
7346   }
7347   PetscFunctionReturn(0);
7348 }
7349 
7350 #undef __FUNCT__
7351 #define __FUNCT__ "DMPlexRefine_Uniform"
7352 /* This will only work for interpolated meshes */
7353 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7354 {
7355   DM              rdm;
7356   PetscInt       *depthSize;
7357   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
7358   PetscErrorCode  ierr;
7359 
7360   PetscFunctionBegin;
7361   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7362   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7363   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7364   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7365   /* Calculate number of new points of each depth */
7366   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7367   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7368   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7369   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7370   /* Step 1: Set chart */
7371   for (d = 0; d <= depth; ++d) {
7372     pEnd += depthSize[d];
7373   }
7374   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7375   /* Step 2: Set cone/support sizes */
7376   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7377   /* Step 3: Setup refined DM */
7378   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7379   /* Step 4: Set cones and supports */
7380   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7381   /* Step 5: Stratify */
7382   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7383   /* Step 6: Set coordinates for vertices */
7384   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7385   /* Step 7: Create pointSF */
7386   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7387   /* Step 8: Create labels */
7388   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7389   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7390 
7391   *dmRefined = rdm;
7392 #if 0
7393   DM_Plex *mesh = (DM_Plex *) dm->data;
7394   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7395   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7396 
7397   PetscFunctionBegin;
7398   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7399   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7400   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7401   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7402   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7403 
7404   /* Count number of new cells which are normal and extra */
7405   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7406   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7407   for (c = cStart; c < cEnd2; ++c) {
7408     PetscInt n;
7409     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7410     newNumCellsNormal += n;
7411   }
7412   for (c = cEnd2; c < cEnd; ++c) {
7413     PetscInt n;
7414     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7415     newNumCellsExtra += n;
7416   }
7417   newNumCells = newNumCellsNormal + newNumCellsExtra;
7418   /* Count number of new vertices which are normal and extra */
7419   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7420   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7421   for (c = cStart; c < cEnd; ++c) {
7422     PetscInt *closure = PETSC_NULL;
7423     PetscInt  closureSize, numCorners = 0, p;
7424 
7425     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7426     for (p = 0; p < closureSize*2; p += 2) {
7427       const PetscInt point = closure[p];
7428       if ((point >= vStart) && (point < vEnd)) {
7429         closure[numCorners++] = point;
7430       }
7431     }
7432     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7433     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7434   }
7435   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7436   for (c = cEnd2; c < cEnd; ++c) {
7437     PetscInt *closure = PETSC_NULL;
7438     PetscInt  closureSize, numCorners = 0, p;
7439 
7440     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7441     for (p = 0; p < closureSize*2; p += 2) {
7442       const PetscInt point = closure[p];
7443       if ((point >= vStart) && (point < vEnd)) {
7444         closure[numCorners++] = point;
7445       }
7446     }
7447     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7448     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7449   } /* for */
7450   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7451   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
7452 
7453 #if 1
7454   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
7455   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
7456   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7457   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7458   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7459   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7460   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7461   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7462   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7463   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7464   ierr = PetscSynchronizedFlush(comm);
7465 #endif
7466 
7467   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7468   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7469   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7470   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7471   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7472   /* Set cone and support sizes for new normal cells */
7473   PetscInt newCell = 0;
7474   for (c = cStart; c < cEnd2; ++c) {
7475     PetscInt coneSize, n, i;
7476 
7477     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7478     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7479     for (i = 0; i < n; ++i, ++newCell) {
7480       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7481     }
7482 
7483     PetscInt *closure = PETSC_NULL;
7484     PetscInt  closureSize, numCorners = 0, p;
7485 
7486     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7487     for (p = 0; p < closureSize*2; p += 2) {
7488       const PetscInt point = closure[p];
7489       if ((point >= vStart) && (point < vEnd)) {
7490         closure[numCorners++] = point;
7491       }
7492     }
7493     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7494     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7495   }
7496 
7497   /* Reset current new cell value and loop over censored cells. */
7498   curNewCell = _orderNewMesh->cellsCensored().min();
7499   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7500   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7501     /* Set new cone and support sizes */
7502     cV.clear();
7503     sieve->cone(*c_iter, cV);
7504     const point_type* cone = cV.getPoints();
7505     const int coneSize = cV.getSize();
7506 
7507     const point_type* newCells;
7508     int numNewCells = 0;
7509     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7510 
7511     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7512       newSieve->setConeSize(curNewCell, coneSize);
7513       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7514         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7515       } /* for */
7516     } /* for */
7517   } /* for */
7518   newSieve->allocate();
7519 
7520   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7521 
7522   /* Create refined cells in new sieve. */
7523   curNewCell = _orderNewMesh->cellsNormal().min();
7524   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7525   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7526     cV.clear();
7527     sieve->cone(*c_iter, cV);
7528     const point_type *cone = cV.getPoints();
7529     const int coneSize = cV.getSize();
7530 
7531     const point_type* newCells;
7532     int numNewCells = 0;
7533     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7534 
7535     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7536       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7537     } /* for */
7538   } /* for */
7539   curNewCell = _orderNewMesh->cellsCensored().min();
7540   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7541   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7542     cV.clear();
7543     sieve->cone(*c_iter, cV);
7544     const point_type *cone = cV.getPoints();
7545     const int coneSize = cV.getSize();
7546 
7547     const point_type* newCells;
7548     int numNewCells = 0;
7549     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7550 
7551     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7552       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7553     } /* for */
7554   } /* for */
7555   newSieve->symmetrize();
7556 
7557   /* Set coordinates in refined mesh. */
7558   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7559   assert(!coordinates.isNull());
7560   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7561   assert(!newCoordinates.isNull());
7562 
7563   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7564   assert(vertices->size() > 0);
7565   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7566   assert(spaceDim > 0);
7567   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7568 
7569   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7570   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7571     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7572   } /* for */
7573   newCoordinates->allocatePoint();
7574 
7575   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7576   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7577     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7578     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7579   } /* for */
7580   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7581   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7582     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7583     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7584   } /* for */
7585 
7586   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7587 
7588   /* Create sensored depth */
7589   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7590   assert(!censoredLabel.isNull());
7591 
7592   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7593 
7594   newSieve->roots(depthVisitor);
7595   while (depthVisitor.isModified()) {
7596     /* FIX: Avoid the copy here somehow by fixing the traversal */
7597     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7598 
7599     depthVisitor.clear();
7600     newSieve->support(modifiedPoints, depthVisitor);
7601   } /* while */
7602   /* Stratify refined mesh */
7603   /* Calculate new point SF */
7604   _calcNewOverlap(newMesh, mesh, refiner);
7605   /* Calculate new labels */
7606   _createLabels(newMesh, mesh, refiner);
7607 #endif
7608   PetscFunctionReturn(0);
7609 }
7610 
7611 #undef __FUNCT__
7612 #define __FUNCT__ "DMPlexSetRefinementUniform"
7613 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7614 {
7615   DM_Plex *mesh = (DM_Plex *) dm->data;
7616 
7617   PetscFunctionBegin;
7618   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7619   mesh->refinementUniform = refinementUniform;
7620   PetscFunctionReturn(0);
7621 }
7622 
7623 #undef __FUNCT__
7624 #define __FUNCT__ "DMPlexGetRefinementUniform"
7625 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7626 {
7627   DM_Plex *mesh = (DM_Plex *) dm->data;
7628 
7629   PetscFunctionBegin;
7630   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7631   PetscValidPointer(refinementUniform,  2);
7632   *refinementUniform = mesh->refinementUniform;
7633   PetscFunctionReturn(0);
7634 }
7635 
7636 #undef __FUNCT__
7637 #define __FUNCT__ "DMPlexSetRefinementLimit"
7638 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7639 {
7640   DM_Plex *mesh = (DM_Plex *) dm->data;
7641 
7642   PetscFunctionBegin;
7643   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7644   mesh->refinementLimit = refinementLimit;
7645   PetscFunctionReturn(0);
7646 }
7647 
7648 #undef __FUNCT__
7649 #define __FUNCT__ "DMPlexGetRefinementLimit"
7650 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7651 {
7652   DM_Plex *mesh = (DM_Plex *) dm->data;
7653 
7654   PetscFunctionBegin;
7655   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7656   PetscValidPointer(refinementLimit,  2);
7657   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7658   *refinementLimit = mesh->refinementLimit;
7659   PetscFunctionReturn(0);
7660 }
7661 
7662 #undef __FUNCT__
7663 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7664 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7665 {
7666   PetscInt       dim, cStart, coneSize, cMax;
7667   PetscErrorCode ierr;
7668 
7669   PetscFunctionBegin;
7670   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7671   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7672   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7673   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7674   switch (dim) {
7675   case 2:
7676     switch (coneSize) {
7677     case 3:
7678       if (cMax >= 0) {
7679         *cellRefiner = 3; /* Hybrid */
7680       } else {
7681         *cellRefiner = 1; /* Triangular */
7682       }
7683       break;
7684     case 4:
7685       if (cMax >= 0) {
7686         *cellRefiner = 4; /* Hybrid */
7687       } else {
7688         *cellRefiner = 2; /* Quadrilateral */
7689       }
7690       break;
7691     default:
7692       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7693     }
7694     break;
7695   default:
7696     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7697   }
7698   PetscFunctionReturn(0);
7699 }
7700 
7701 #undef __FUNCT__
7702 #define __FUNCT__ "DMRefine_Plex"
7703 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7704 {
7705   PetscReal      refinementLimit;
7706   PetscInt       dim, cStart, cEnd;
7707   char           genname[1024], *name = PETSC_NULL;
7708   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7709   PetscErrorCode ierr;
7710 
7711   PetscFunctionBegin;
7712   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7713   if (isUniform) {
7714     CellRefiner cellRefiner;
7715 
7716     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7717     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7718     PetscFunctionReturn(0);
7719   }
7720   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7721   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7722   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7723   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7724   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7725   if (flg) {name = genname;}
7726   if (name) {
7727     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7728     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7729     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7730   }
7731   switch (dim) {
7732   case 2:
7733     if (!name || isTriangle) {
7734 #if defined(PETSC_HAVE_TRIANGLE)
7735       double  *maxVolumes;
7736       PetscInt c;
7737 
7738       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7739       for (c = 0; c < cEnd-cStart; ++c) {
7740         maxVolumes[c] = refinementLimit;
7741       }
7742       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7743 #else
7744       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7745 #endif
7746     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7747     break;
7748   case 3:
7749     if (!name || isCTetgen) {
7750 #if defined(PETSC_HAVE_CTETGEN)
7751       PetscReal *maxVolumes;
7752       PetscInt   c;
7753 
7754       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7755       for (c = 0; c < cEnd-cStart; ++c) {
7756         maxVolumes[c] = refinementLimit;
7757       }
7758       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7759 #else
7760       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7761 #endif
7762     } else if (isTetgen) {
7763 #if defined(PETSC_HAVE_TETGEN)
7764       double  *maxVolumes;
7765       PetscInt c;
7766 
7767       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7768       for (c = 0; c < cEnd-cStart; ++c) {
7769         maxVolumes[c] = refinementLimit;
7770       }
7771       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7772 #else
7773       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7774 #endif
7775     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7776     break;
7777   default:
7778     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7779   }
7780   PetscFunctionReturn(0);
7781 }
7782 
7783 #undef __FUNCT__
7784 #define __FUNCT__ "DMPlexGetDepth"
7785 /*@
7786   DMPlexGetDepth - get the number of strata
7787 
7788   Not Collective
7789 
7790   Input Parameters:
7791 . dm           - The DMPlex object
7792 
7793   Output Parameters:
7794 . depth - number of strata
7795 
7796   Level: developer
7797 
7798   Notes:
7799   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7800 
7801 .keywords: mesh, points
7802 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7803 @*/
7804 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7805 {
7806   PetscInt       d;
7807   PetscErrorCode ierr;
7808 
7809   PetscFunctionBegin;
7810   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7811   PetscValidPointer(depth, 2);
7812   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7813   *depth = d-1;
7814   PetscFunctionReturn(0);
7815 }
7816 
7817 #undef __FUNCT__
7818 #define __FUNCT__ "DMPlexGetDepthStratum"
7819 /*@
7820   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7821 
7822   Not Collective
7823 
7824   Input Parameters:
7825 + dm           - The DMPlex object
7826 - stratumValue - The requested depth
7827 
7828   Output Parameters:
7829 + start - The first point at this depth
7830 - end   - One beyond the last point at this depth
7831 
7832   Level: developer
7833 
7834 .keywords: mesh, points
7835 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7836 @*/
7837 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7838 {
7839   DM_Plex    *mesh = (DM_Plex *) dm->data;
7840   DMLabel        next = mesh->labels;
7841   PetscBool      flg  = PETSC_FALSE;
7842   PetscInt       depth;
7843   PetscErrorCode ierr;
7844 
7845   PetscFunctionBegin;
7846   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7847   if (stratumValue < 0) {
7848     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7849     PetscFunctionReturn(0);
7850   } else {
7851     PetscInt pStart, pEnd;
7852 
7853     if (start) {*start = 0;}
7854     if (end)   {*end   = 0;}
7855     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7856     if (pStart == pEnd) {PetscFunctionReturn(0);}
7857   }
7858   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7859   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7860   /* We should have a generic GetLabel() and a Label class */
7861   while (next) {
7862     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7863     if (flg) break;
7864     next = next->next;
7865   }
7866   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7867   depth = stratumValue;
7868   if ((depth < 0) || (depth >= next->numStrata)) {
7869     if (start) {*start = 0;}
7870     if (end)   {*end   = 0;}
7871   } else {
7872     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7873     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7874   }
7875   PetscFunctionReturn(0);
7876 }
7877 
7878 #undef __FUNCT__
7879 #define __FUNCT__ "DMPlexGetHeightStratum"
7880 /*@
7881   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7882 
7883   Not Collective
7884 
7885   Input Parameters:
7886 + dm           - The DMPlex object
7887 - stratumValue - The requested height
7888 
7889   Output Parameters:
7890 + start - The first point at this height
7891 - end   - One beyond the last point at this height
7892 
7893   Level: developer
7894 
7895 .keywords: mesh, points
7896 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7897 @*/
7898 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7899 {
7900   DM_Plex        *mesh = (DM_Plex *) dm->data;
7901   DMLabel        next = mesh->labels;
7902   PetscBool      flg  = PETSC_FALSE;
7903   PetscInt       depth;
7904   PetscErrorCode ierr;
7905 
7906   PetscFunctionBegin;
7907   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7908   if (stratumValue < 0) {
7909     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7910   } else {
7911     PetscInt pStart, pEnd;
7912 
7913     if (start) {*start = 0;}
7914     if (end)   {*end   = 0;}
7915     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7916     if (pStart == pEnd) {PetscFunctionReturn(0);}
7917   }
7918   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7919   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7920   /* We should have a generic GetLabel() and a Label class */
7921   while (next) {
7922     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7923     if (flg) break;
7924     next = next->next;
7925   }
7926   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7927   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7928   if ((depth < 0) || (depth >= next->numStrata)) {
7929     if (start) {*start = 0;}
7930     if (end)   {*end   = 0;}
7931   } else {
7932     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7933     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7934   }
7935   PetscFunctionReturn(0);
7936 }
7937 
7938 #undef __FUNCT__
7939 #define __FUNCT__ "DMPlexCreateSectionInitial"
7940 /* Set the number of dof on each point and separate by fields */
7941 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7942 {
7943   PetscInt      *numDofTot;
7944   PetscInt       pStart = 0, pEnd = 0;
7945   PetscInt       p, d, f;
7946   PetscErrorCode ierr;
7947 
7948   PetscFunctionBegin;
7949   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
7950   for (d = 0; d <= dim; ++d) {
7951     numDofTot[d] = 0;
7952     for (f = 0; f < numFields; ++f) {
7953       numDofTot[d] += numDof[f*(dim+1)+d];
7954     }
7955   }
7956   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
7957   if (numFields > 0) {
7958     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
7959     if (numComp) {
7960       for (f = 0; f < numFields; ++f) {
7961         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
7962       }
7963     }
7964   }
7965   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7966   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
7967   for (d = 0; d <= dim; ++d) {
7968     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
7969     for (p = pStart; p < pEnd; ++p) {
7970       for (f = 0; f < numFields; ++f) {
7971         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
7972       }
7973       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
7974     }
7975   }
7976   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
7977   PetscFunctionReturn(0);
7978 }
7979 
7980 #undef __FUNCT__
7981 #define __FUNCT__ "DMPlexCreateSectionBCDof"
7982 /* Set the number of dof on each point and separate by fields
7983    If constDof is PETSC_DETERMINE, constrain every dof on the point
7984 */
7985 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
7986 {
7987   PetscInt       numFields;
7988   PetscInt       bc;
7989   PetscErrorCode ierr;
7990 
7991   PetscFunctionBegin;
7992   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7993   for (bc = 0; bc < numBC; ++bc) {
7994     PetscInt        field = 0;
7995     const PetscInt *idx;
7996     PetscInt        n, i;
7997 
7998     if (numFields) {field = bcField[bc];}
7999     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
8000     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8001     for (i = 0; i < n; ++i) {
8002       const PetscInt p = idx[i];
8003       PetscInt       numConst = constDof;
8004 
8005       /* Constrain every dof on the point */
8006       if (numConst < 0) {
8007         if (numFields) {
8008           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
8009         } else {
8010           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
8011         }
8012       }
8013       if (numFields) {
8014         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
8015       }
8016       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
8017     }
8018     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8019   }
8020   PetscFunctionReturn(0);
8021 }
8022 
8023 #undef __FUNCT__
8024 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
8025 /* Set the constrained indices on each point and separate by fields */
8026 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
8027 {
8028   PetscInt      *maxConstraints;
8029   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
8030   PetscErrorCode ierr;
8031 
8032   PetscFunctionBegin;
8033   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8034   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8035   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
8036   for (f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
8037   for (p = pStart; p < pEnd; ++p) {
8038     PetscInt cdof;
8039 
8040     if (numFields) {
8041       for (f = 0; f < numFields; ++f) {
8042         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
8043         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
8044       }
8045     } else {
8046       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8047       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
8048     }
8049   }
8050   for (f = 0; f < numFields; ++f) {
8051     maxConstraints[numFields] += maxConstraints[f];
8052   }
8053   if (maxConstraints[numFields]) {
8054     PetscInt *indices;
8055 
8056     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8057     for (p = pStart; p < pEnd; ++p) {
8058       PetscInt cdof, d;
8059 
8060       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8061       if (cdof) {
8062         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
8063         if (numFields) {
8064           PetscInt numConst = 0, foff = 0;
8065 
8066           for (f = 0; f < numFields; ++f) {
8067             PetscInt cfdof, fdof;
8068 
8069             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8070             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
8071             /* Change constraint numbering from absolute local dof number to field relative local dof number */
8072             for (d = 0; d < cfdof; ++d) {
8073               indices[numConst+d] = d;
8074             }
8075             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
8076             for (d = 0; d < cfdof; ++d) {
8077               indices[numConst+d] += foff;
8078             }
8079             numConst += cfdof;
8080             foff     += fdof;
8081           }
8082           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8083         } else {
8084           for (d = 0; d < cdof; ++d) {
8085             indices[d] = d;
8086           }
8087         }
8088         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8089       }
8090     }
8091     ierr = PetscFree(indices);CHKERRQ(ierr);
8092   }
8093   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
8094   PetscFunctionReturn(0);
8095 }
8096 
8097 #undef __FUNCT__
8098 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
8099 /* Set the constrained field indices on each point */
8100 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
8101 {
8102   const PetscInt *points, *indices;
8103   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
8104   PetscErrorCode  ierr;
8105 
8106   PetscFunctionBegin;
8107   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8108   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8109 
8110   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8111   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8112   if (!constraintIndices) {
8113     PetscInt *idx, i;
8114 
8115     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8116     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8117     for (i = 0; i < maxDof; ++i) {idx[i] = i;}
8118     for (p = 0; p < numPoints; ++p) {
8119       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8120     }
8121     ierr = PetscFree(idx);CHKERRQ(ierr);
8122   } else {
8123     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8124     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8125     for (p = 0; p < numPoints; ++p) {
8126       PetscInt fcdof;
8127 
8128       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8129       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);
8130       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8131     }
8132     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8133   }
8134   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8135   PetscFunctionReturn(0);
8136 }
8137 
8138 #undef __FUNCT__
8139 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8140 /* Set the constrained indices on each point and separate by fields */
8141 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8142 {
8143   PetscInt      *indices;
8144   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8145   PetscErrorCode ierr;
8146 
8147   PetscFunctionBegin;
8148   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8149   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8150   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8151   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8152   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8153   for (p = pStart; p < pEnd; ++p) {
8154     PetscInt cdof, d;
8155 
8156     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8157     if (cdof) {
8158       PetscInt numConst = 0, foff = 0;
8159 
8160       for (f = 0; f < numFields; ++f) {
8161         const PetscInt *fcind;
8162         PetscInt        fdof, fcdof;
8163 
8164         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8165         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8166         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8167         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8168         for (d = 0; d < fcdof; ++d) {
8169           indices[numConst+d] = fcind[d]+foff;
8170         }
8171         foff     += fdof;
8172         numConst += fcdof;
8173       }
8174       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8175       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8176     }
8177   }
8178   ierr = PetscFree(indices);CHKERRQ(ierr);
8179   PetscFunctionReturn(0);
8180 }
8181 
8182 #undef __FUNCT__
8183 #define __FUNCT__ "DMPlexCreateSection"
8184 /*@C
8185   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8186 
8187   Not Collective
8188 
8189   Input Parameters:
8190 + dm        - The DMPlex object
8191 . dim       - The spatial dimension of the problem
8192 . numFields - The number of fields in the problem
8193 . numComp   - An array of size numFields that holds the number of components for each field
8194 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8195 . numBC     - The number of boundary conditions
8196 . bcField   - An array of size numBC giving the field number for each boundry condition
8197 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8198 
8199   Output Parameter:
8200 . section - The PetscSection object
8201 
8202   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
8203   nubmer of dof for field 0 on each edge.
8204 
8205   Level: developer
8206 
8207 .keywords: mesh, elements
8208 .seealso: DMPlexCreate(), PetscSectionCreate()
8209 @*/
8210 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8211 {
8212   PetscErrorCode ierr;
8213 
8214   PetscFunctionBegin;
8215   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8216   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8217   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8218   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8219   {
8220     PetscBool view = PETSC_FALSE;
8221 
8222     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8223     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8224   }
8225   PetscFunctionReturn(0);
8226 }
8227 
8228 #undef __FUNCT__
8229 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8230 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8231 {
8232   PetscSection   section;
8233   PetscErrorCode ierr;
8234 
8235   PetscFunctionBegin;
8236   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8237   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8238   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8239   PetscFunctionReturn(0);
8240 }
8241 
8242 #undef __FUNCT__
8243 #define __FUNCT__ "DMPlexGetCoordinateSection"
8244 /*@
8245   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8246 
8247   Not Collective
8248 
8249   Input Parameter:
8250 . dm - The DMPlex object
8251 
8252   Output Parameter:
8253 . section - The PetscSection object
8254 
8255   Level: intermediate
8256 
8257 .keywords: mesh, coordinates
8258 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8259 @*/
8260 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8261 {
8262   DM             cdm;
8263   PetscErrorCode ierr;
8264 
8265   PetscFunctionBegin;
8266   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8267   PetscValidPointer(section, 2);
8268   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8269   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8270   PetscFunctionReturn(0);
8271 }
8272 
8273 #undef __FUNCT__
8274 #define __FUNCT__ "DMPlexSetCoordinateSection"
8275 /*@
8276   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8277 
8278   Not Collective
8279 
8280   Input Parameters:
8281 + dm      - The DMPlex object
8282 - section - The PetscSection object
8283 
8284   Level: intermediate
8285 
8286 .keywords: mesh, coordinates
8287 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8288 @*/
8289 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8290 {
8291   DM             cdm;
8292   PetscErrorCode ierr;
8293 
8294   PetscFunctionBegin;
8295   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8296   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8297   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8298   PetscFunctionReturn(0);
8299 }
8300 
8301 #undef __FUNCT__
8302 #define __FUNCT__ "DMPlexGetConeSection"
8303 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8304 {
8305   DM_Plex *mesh = (DM_Plex *) dm->data;
8306 
8307   PetscFunctionBegin;
8308   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8309   if (section) *section = mesh->coneSection;
8310   PetscFunctionReturn(0);
8311 }
8312 
8313 #undef __FUNCT__
8314 #define __FUNCT__ "DMPlexGetCones"
8315 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8316 {
8317   DM_Plex *mesh = (DM_Plex *) dm->data;
8318 
8319   PetscFunctionBegin;
8320   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8321   if (cones) *cones = mesh->cones;
8322   PetscFunctionReturn(0);
8323 }
8324 
8325 #undef __FUNCT__
8326 #define __FUNCT__ "DMPlexGetConeOrientations"
8327 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8328 {
8329   DM_Plex *mesh = (DM_Plex *) dm->data;
8330 
8331   PetscFunctionBegin;
8332   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8333   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8334   PetscFunctionReturn(0);
8335 }
8336 
8337 #undef __FUNCT__
8338 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8339 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8340 {
8341   const PetscInt embedDim = 2;
8342   PetscReal      x = PetscRealPart(point[0]);
8343   PetscReal      y = PetscRealPart(point[1]);
8344   PetscReal      v0[2], J[4], invJ[4], detJ;
8345   PetscReal      xi, eta;
8346   PetscErrorCode ierr;
8347 
8348   PetscFunctionBegin;
8349   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8350   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8351   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8352 
8353   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
8354     *cell = c;
8355   } else {
8356     *cell = -1;
8357   }
8358   PetscFunctionReturn(0);
8359 }
8360 
8361 #undef __FUNCT__
8362 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8363 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8364 {
8365   PetscSection       coordSection;
8366   Vec                coordsLocal;
8367   const PetscScalar *coords;
8368   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8369   PetscReal          x         = PetscRealPart(point[0]);
8370   PetscReal          y         = PetscRealPart(point[1]);
8371   PetscInt           crossings = 0, f;
8372   PetscErrorCode     ierr;
8373 
8374   PetscFunctionBegin;
8375   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8376   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8377   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8378   for (f = 0; f < 4; ++f) {
8379     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8380     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8381     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8382     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8383     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8384     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8385     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8386     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8387     if ((cond1 || cond2)  && above) ++crossings;
8388   }
8389   if (crossings % 2) {
8390     *cell = c;
8391   } else {
8392     *cell = -1;
8393   }
8394   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8395   PetscFunctionReturn(0);
8396 }
8397 
8398 #undef __FUNCT__
8399 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8400 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8401 {
8402   const PetscInt embedDim = 3;
8403   PetscReal      v0[3], J[9], invJ[9], detJ;
8404   PetscReal      x = PetscRealPart(point[0]);
8405   PetscReal      y = PetscRealPart(point[1]);
8406   PetscReal      z = PetscRealPart(point[2]);
8407   PetscReal      xi, eta, zeta;
8408   PetscErrorCode ierr;
8409 
8410   PetscFunctionBegin;
8411   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8412   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8413   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8414   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8415 
8416   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
8417     *cell = c;
8418   } else {
8419     *cell = -1;
8420   }
8421   PetscFunctionReturn(0);
8422 }
8423 
8424 #undef __FUNCT__
8425 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8426 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8427 {
8428   PetscSection       coordSection;
8429   Vec                coordsLocal;
8430   const PetscScalar *coords;
8431   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8432                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8433   PetscBool          found     = PETSC_TRUE;
8434   PetscInt           f;
8435   PetscErrorCode     ierr;
8436 
8437   PetscFunctionBegin;
8438   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8439   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8440   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8441   for (f = 0; f < 6; ++f) {
8442     /* Check the point is under plane */
8443     /*   Get face normal */
8444     PetscReal v_i[3];
8445     PetscReal v_j[3];
8446     PetscReal normal[3];
8447     PetscReal pp[3];
8448     PetscReal dot;
8449 
8450     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8451     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8452     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8453     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8454     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8455     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8456     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8457     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8458     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8459     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8460     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8461     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8462     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8463 
8464     /* Check that projected point is in face (2D location problem) */
8465     if (dot < 0.0) {
8466       found = PETSC_FALSE;
8467       break;
8468     }
8469   }
8470   if (found) {
8471     *cell = c;
8472   } else {
8473     *cell = -1;
8474   }
8475   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8476   PetscFunctionReturn(0);
8477 }
8478 
8479 #undef __FUNCT__
8480 #define __FUNCT__ "DMLocatePoints_Plex"
8481 /*
8482  Need to implement using the guess
8483 */
8484 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8485 {
8486   PetscInt       cell = -1/*, guess = -1*/;
8487   PetscInt       bs, numPoints, p;
8488   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8489   PetscInt      *cells;
8490   PetscScalar   *a;
8491   PetscErrorCode ierr;
8492 
8493   PetscFunctionBegin;
8494   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8495   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8496   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8497   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8498   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8499   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8500   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8501   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);
8502   numPoints /= bs;
8503   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8504   for (p = 0; p < numPoints; ++p) {
8505     const PetscScalar *point = &a[p*bs];
8506 
8507     switch (dim) {
8508     case 2:
8509       for (c = cStart; c < cEnd; ++c) {
8510         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8511         switch (coneSize) {
8512         case 3:
8513           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8514           break;
8515         case 4:
8516           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8517           break;
8518         default:
8519           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8520         }
8521         if (cell >= 0) break;
8522       }
8523       break;
8524     case 3:
8525       for (c = cStart; c < cEnd; ++c) {
8526         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8527         switch (coneSize) {
8528         case 4:
8529           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8530           break;
8531         case 8:
8532           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8533           break;
8534         default:
8535           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8536         }
8537         if (cell >= 0) break;
8538       }
8539       break;
8540     default:
8541       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8542     }
8543     cells[p] = cell;
8544   }
8545   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8546   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8547   PetscFunctionReturn(0);
8548 }
8549 
8550 /******************************** FEM Support **********************************/
8551 
8552 #undef __FUNCT__
8553 #define __FUNCT__ "DMPlexVecGetClosure"
8554 /*@C
8555   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8556 
8557   Not collective
8558 
8559   Input Parameters:
8560 + dm - The DM
8561 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8562 . v - The local vector
8563 - point - The sieve point in the DM
8564 
8565   Output Parameters:
8566 + csize - The number of values in the closure, or PETSC_NULL
8567 - values - The array of values, which is a borrowed array and should not be freed
8568 
8569   Level: intermediate
8570 
8571 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8572 @*/
8573 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8574 {
8575   PetscScalar    *array, *vArray;
8576   PetscInt       *points = PETSC_NULL;
8577   PetscInt        offsets[32];
8578   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8579   PetscErrorCode  ierr;
8580 
8581   PetscFunctionBegin;
8582   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8583   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8584   if (!section) {
8585     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8586   }
8587   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8588   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8589   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8590   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8591   /* Compress out points not in the section */
8592   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8593   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8594     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8595       points[q*2]   = points[p];
8596       points[q*2+1] = points[p+1];
8597       ++q;
8598     }
8599   }
8600   numPoints = q;
8601   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8602     PetscInt dof, fdof;
8603 
8604     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8605     for (f = 0; f < numFields; ++f) {
8606       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8607       offsets[f+1] += fdof;
8608     }
8609     size += dof;
8610   }
8611   for (f = 1; f < numFields; ++f) {
8612     offsets[f+1] += offsets[f];
8613   }
8614   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8615   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8616   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8617   for (p = 0; p < numPoints*2; p += 2) {
8618     PetscInt     o = points[p+1];
8619     PetscInt     dof, off, d;
8620     PetscScalar *varr;
8621 
8622     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8623     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8624     varr = &vArray[off];
8625     if (numFields) {
8626       PetscInt fdof, foff, fcomp, f, c;
8627 
8628       for (f = 0, foff = 0; f < numFields; ++f) {
8629         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8630         if (o >= 0) {
8631           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8632             array[offsets[f]] = varr[foff+d];
8633           }
8634         } else {
8635           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8636           for (d = fdof/fcomp-1; d >= 0; --d) {
8637             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8638               array[offsets[f]] = varr[foff+d*fcomp+c];
8639             }
8640           }
8641         }
8642         foff += fdof;
8643       }
8644     } else {
8645       if (o >= 0) {
8646         for (d = 0; d < dof; ++d, ++offsets[0]) {
8647           array[offsets[0]] = varr[d];
8648         }
8649       } else {
8650         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8651           array[offsets[0]] = varr[d];
8652         }
8653       }
8654     }
8655   }
8656   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8657   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8658   if (csize) *csize = size;
8659   *values = array;
8660   PetscFunctionReturn(0);
8661 }
8662 
8663 #undef __FUNCT__
8664 #define __FUNCT__ "DMPlexVecRestoreClosure"
8665 /*@C
8666   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8667 
8668   Not collective
8669 
8670   Input Parameters:
8671 + dm - The DM
8672 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8673 . v - The local vector
8674 . point - The sieve point in the DM
8675 . csize - The number of values in the closure, or PETSC_NULL
8676 - values - The array of values, which is a borrowed array and should not be freed
8677 
8678   Level: intermediate
8679 
8680 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8681 @*/
8682 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8683 {
8684   PetscInt        size = 0;
8685   PetscErrorCode  ierr;
8686 
8687   PetscFunctionBegin;
8688   /* Should work without recalculating size */
8689   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8690   PetscFunctionReturn(0);
8691 }
8692 
8693 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8694 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8695 
8696 #undef __FUNCT__
8697 #define __FUNCT__ "updatePoint_private"
8698 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8699 {
8700   PetscInt        cdof;  /* The number of constraints on this point */
8701   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8702   PetscScalar    *a;
8703   PetscInt        off, cind = 0, k;
8704   PetscErrorCode  ierr;
8705 
8706   PetscFunctionBegin;
8707   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8708   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8709   a    = &array[off];
8710   if (!cdof || setBC) {
8711     if (orientation >= 0) {
8712       for (k = 0; k < dof; ++k) {
8713         fuse(&a[k], values[k]);
8714       }
8715     } else {
8716       for (k = 0; k < dof; ++k) {
8717         fuse(&a[k], values[dof-k-1]);
8718       }
8719     }
8720   } else {
8721     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8722     if (orientation >= 0) {
8723       for (k = 0; k < dof; ++k) {
8724         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8725         fuse(&a[k], values[k]);
8726       }
8727     } else {
8728       for (k = 0; k < dof; ++k) {
8729         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8730         fuse(&a[k], values[dof-k-1]);
8731       }
8732     }
8733   }
8734   PetscFunctionReturn(0);
8735 }
8736 
8737 #undef __FUNCT__
8738 #define __FUNCT__ "updatePointFields_private"
8739 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8740 {
8741   PetscScalar   *a;
8742   PetscInt       numFields, off, foff, f;
8743   PetscErrorCode ierr;
8744 
8745   PetscFunctionBegin;
8746   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8747   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8748   a    = &array[off];
8749   for (f = 0, foff = 0; f < numFields; ++f) {
8750     PetscInt        fdof, fcomp, fcdof;
8751     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8752     PetscInt        cind = 0, k, c;
8753 
8754     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8755     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8756     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8757     if (!fcdof || setBC) {
8758       if (orientation >= 0) {
8759         for (k = 0; k < fdof; ++k) {
8760           fuse(&a[foff+k], values[foffs[f]+k]);
8761         }
8762       } else {
8763         for (k = fdof/fcomp-1; k >= 0; --k) {
8764           for (c = 0; c < fcomp; ++c) {
8765             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8766           }
8767         }
8768       }
8769     } else {
8770       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8771       if (orientation >= 0) {
8772         for (k = 0; k < fdof; ++k) {
8773           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8774           fuse(&a[foff+k], values[foffs[f]+k]);
8775         }
8776       } else {
8777         for (k = fdof/fcomp-1; k >= 0; --k) {
8778           for (c = 0; c < fcomp; ++c) {
8779             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8780             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8781           }
8782         }
8783       }
8784     }
8785     foff     += fdof;
8786     foffs[f] += fdof;
8787   }
8788   PetscFunctionReturn(0);
8789 }
8790 
8791 #undef __FUNCT__
8792 #define __FUNCT__ "DMPlexVecSetClosure"
8793 /*@C
8794   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8795 
8796   Not collective
8797 
8798   Input Parameters:
8799 + dm - The DM
8800 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8801 . v - The local vector
8802 . point - The sieve point in the DM
8803 . values - The array of values, which is a borrowed array and should not be freed
8804 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8805 
8806   Level: intermediate
8807 
8808 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8809 @*/
8810 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8811 {
8812   PetscScalar    *array;
8813   PetscInt       *points = PETSC_NULL;
8814   PetscInt        offsets[32];
8815   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8816   PetscErrorCode  ierr;
8817 
8818   PetscFunctionBegin;
8819   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8820   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8821   if (!section) {
8822     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8823   }
8824   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8825   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8826   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8827   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8828   /* Compress out points not in the section */
8829   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8830   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8831     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8832       points[q*2]   = points[p];
8833       points[q*2+1] = points[p+1];
8834       ++q;
8835     }
8836   }
8837   numPoints = q;
8838   for (p = 0; p < numPoints*2; p += 2) {
8839     PetscInt fdof;
8840 
8841     for (f = 0; f < numFields; ++f) {
8842       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8843       offsets[f+1] += fdof;
8844     }
8845   }
8846   for (f = 1; f < numFields; ++f) {
8847     offsets[f+1] += offsets[f];
8848   }
8849   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8850   if (numFields) {
8851     switch (mode) {
8852     case INSERT_VALUES:
8853       for (p = 0; p < numPoints*2; p += 2) {
8854         PetscInt o = points[p+1];
8855         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8856       } break;
8857     case INSERT_ALL_VALUES:
8858       for (p = 0; p < numPoints*2; p += 2) {
8859         PetscInt o = points[p+1];
8860         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8861       } break;
8862     case ADD_VALUES:
8863       for (p = 0; p < numPoints*2; p += 2) {
8864         PetscInt o = points[p+1];
8865         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8866       } break;
8867     case ADD_ALL_VALUES:
8868       for (p = 0; p < numPoints*2; p += 2) {
8869         PetscInt o = points[p+1];
8870         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8871       } break;
8872     default:
8873       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8874     }
8875   } else {
8876     switch (mode) {
8877     case INSERT_VALUES:
8878       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8879         PetscInt o = points[p+1];
8880         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8881         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8882       } break;
8883     case INSERT_ALL_VALUES:
8884       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8885         PetscInt o = points[p+1];
8886         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8887         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8888       } break;
8889     case ADD_VALUES:
8890       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8891         PetscInt o = points[p+1];
8892         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8893         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8894       } break;
8895     case ADD_ALL_VALUES:
8896       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8897         PetscInt o = points[p+1];
8898         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8899         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8900       } break;
8901     default:
8902       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8903     }
8904   }
8905   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8906   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8907   PetscFunctionReturn(0);
8908 }
8909 
8910 #undef __FUNCT__
8911 #define __FUNCT__ "DMPlexPrintMatSetValues"
8912 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8913 {
8914   PetscMPIInt    rank;
8915   PetscInt       i, j;
8916   PetscErrorCode ierr;
8917 
8918   PetscFunctionBegin;
8919   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8920   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8921   for (i = 0; i < numIndices; i++) {
8922     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8923   }
8924   for (i = 0; i < numIndices; i++) {
8925     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8926     for (j = 0; j < numIndices; j++) {
8927 #if defined(PETSC_USE_COMPLEX)
8928       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8929 #else
8930       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8931 #endif
8932     }
8933     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8934   }
8935   PetscFunctionReturn(0);
8936 }
8937 
8938 #undef __FUNCT__
8939 #define __FUNCT__ "indicesPoint_private"
8940 /* . off - The global offset of this point */
8941 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8942 {
8943   PetscInt        cdof;  /* The number of constraints on this point */
8944   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8945   PetscInt        cind = 0, k;
8946   PetscErrorCode  ierr;
8947 
8948   PetscFunctionBegin;
8949   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
8950   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8951   if (!cdof || setBC) {
8952     if (orientation >= 0) {
8953       for (k = 0; k < dof; ++k) {
8954         indices[k] = off+k;
8955       }
8956     } else {
8957       for (k = 0; k < dof; ++k) {
8958         indices[dof-k-1] = off+k;
8959       }
8960     }
8961   } else {
8962     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8963     if (orientation >= 0) {
8964       for (k = 0; k < dof; ++k) {
8965         if ((cind < cdof) && (k == cdofs[cind])) {
8966           /* Insert check for returning constrained indices */
8967           indices[k] = -(off+k+1);
8968           ++cind;
8969         } else {
8970           indices[k] = off+k-cind;
8971         }
8972       }
8973     } else {
8974       for (k = 0; k < dof; ++k) {
8975         if ((cind < cdof) && (k == cdofs[cind])) {
8976           /* Insert check for returning constrained indices */
8977           indices[dof-k-1] = -(off+k+1);
8978           ++cind;
8979         } else {
8980           indices[dof-k-1] = off+k-cind;
8981         }
8982       }
8983     }
8984   }
8985   PetscFunctionReturn(0);
8986 }
8987 
8988 #undef __FUNCT__
8989 #define __FUNCT__ "indicesPointFields_private"
8990 /* . off - The global offset of this point */
8991 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
8992 {
8993   PetscInt       numFields, foff, f;
8994   PetscErrorCode ierr;
8995 
8996   PetscFunctionBegin;
8997   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8998   for (f = 0, foff = 0; f < numFields; ++f) {
8999     PetscInt        fdof, fcomp, cfdof;
9000     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
9001     PetscInt        cind = 0, k, c;
9002 
9003     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
9004     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
9005     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
9006     if (!cfdof || setBC) {
9007       if (orientation >= 0) {
9008         for (k = 0; k < fdof; ++k) {
9009           indices[foffs[f]+k] = off+foff+k;
9010         }
9011       } else {
9012         for (k = fdof/fcomp-1; k >= 0; --k) {
9013           for (c = 0; c < fcomp; ++c) {
9014             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
9015           }
9016         }
9017       }
9018     } else {
9019       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
9020       if (orientation >= 0) {
9021         for (k = 0; k < fdof; ++k) {
9022           if ((cind < cfdof) && (k == fcdofs[cind])) {
9023             indices[foffs[f]+k] = -(off+foff+k+1);
9024             ++cind;
9025           } else {
9026             indices[foffs[f]+k] = off+foff+k-cind;
9027           }
9028         }
9029       } else {
9030         for (k = fdof/fcomp-1; k >= 0; --k) {
9031           for (c = 0; c < fcomp; ++c) {
9032             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
9033               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
9034               ++cind;
9035             } else {
9036               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
9037             }
9038           }
9039         }
9040       }
9041     }
9042     foff     += fdof - cfdof;
9043     foffs[f] += fdof;
9044   }
9045   PetscFunctionReturn(0);
9046 }
9047 
9048 #undef __FUNCT__
9049 #define __FUNCT__ "DMPlexMatSetClosure"
9050 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
9051 {
9052   DM_Plex     *mesh   = (DM_Plex *) dm->data;
9053   PetscInt       *points = PETSC_NULL;
9054   PetscInt       *indices;
9055   PetscInt        offsets[32];
9056   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
9057   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
9058   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
9059   PetscErrorCode  ierr;
9060 
9061   PetscFunctionBegin;
9062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9063   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
9064   if (useDefault) {
9065     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9066   }
9067   if (useGlobalDefault) {
9068     if (useDefault) {
9069       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
9070     } else {
9071       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9072     }
9073   }
9074   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9075   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
9076   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
9077   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9078   /* Compress out points not in the section */
9079   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
9080   for (p = 0, q = 0; p < numPoints*2; p += 2) {
9081     if ((points[p] >= pStart) && (points[p] < pEnd)) {
9082       points[q*2]   = points[p];
9083       points[q*2+1] = points[p+1];
9084       ++q;
9085     }
9086   }
9087   numPoints = q;
9088   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
9089     PetscInt fdof;
9090 
9091     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
9092     for (f = 0; f < numFields; ++f) {
9093       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
9094       offsets[f+1] += fdof;
9095     }
9096     numIndices += dof;
9097   }
9098   for (f = 1; f < numFields; ++f) {
9099     offsets[f+1] += offsets[f];
9100   }
9101   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
9102   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9103   if (numFields) {
9104     for (p = 0; p < numPoints*2; p += 2) {
9105       PetscInt o = points[p+1];
9106       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9107       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
9108     }
9109   } else {
9110     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
9111       PetscInt o = points[p+1];
9112       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9113       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
9114     }
9115   }
9116   if (useGlobalDefault && !useDefault) {
9117     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9118   }
9119   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
9120   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9121   if (ierr) {
9122     PetscMPIInt    rank;
9123     PetscErrorCode ierr2;
9124 
9125     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
9126     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9127     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9128     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9129     CHKERRQ(ierr);
9130   }
9131   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9132   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9133   PetscFunctionReturn(0);
9134 }
9135 
9136 #undef __FUNCT__
9137 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9138 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9139 {
9140   PetscSection       coordSection;
9141   Vec                coordinates;
9142   const PetscScalar *coords;
9143   const PetscInt     dim = 2;
9144   PetscInt           d, f;
9145   PetscErrorCode     ierr;
9146 
9147   PetscFunctionBegin;
9148   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9149   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9150   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9151   if (v0) {
9152     for (d = 0; d < dim; d++) {
9153       v0[d] = PetscRealPart(coords[d]);
9154     }
9155   }
9156   if (J) {
9157     for (d = 0; d < dim; d++) {
9158       for (f = 0; f < dim; f++) {
9159         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9160       }
9161     }
9162     *detJ = J[0]*J[3] - J[1]*J[2];
9163 #if 0
9164     if (detJ < 0.0) {
9165       const PetscReal xLength = mesh->periodicity[0];
9166 
9167       if (xLength != 0.0) {
9168         PetscReal v0x = coords[0*dim+0];
9169 
9170         if (v0x == 0.0) {
9171           v0x = v0[0] = xLength;
9172         }
9173         for (f = 0; f < dim; f++) {
9174           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9175 
9176           J[0*dim+f] = 0.5*(px - v0x);
9177         }
9178       }
9179       detJ = J[0]*J[3] - J[1]*J[2];
9180     }
9181 #endif
9182     PetscLogFlops(8.0 + 3.0);
9183   }
9184   if (invJ) {
9185     const PetscReal invDet = 1.0/(*detJ);
9186 
9187     invJ[0] =  invDet*J[3];
9188     invJ[1] = -invDet*J[1];
9189     invJ[2] = -invDet*J[2];
9190     invJ[3] =  invDet*J[0];
9191     PetscLogFlops(5.0);
9192   }
9193   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9194   PetscFunctionReturn(0);
9195 }
9196 
9197 #undef __FUNCT__
9198 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9199 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9200 {
9201   PetscSection       coordSection;
9202   Vec                coordinates;
9203   const PetscScalar *coords;
9204   const PetscInt     dim = 2;
9205   PetscInt           d, f;
9206   PetscErrorCode     ierr;
9207 
9208   PetscFunctionBegin;
9209   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9210   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9211   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9212   if (v0) {
9213     for (d = 0; d < dim; d++) {
9214       v0[d] = PetscRealPart(coords[d]);
9215     }
9216   }
9217   if (J) {
9218     for (d = 0; d < dim; d++) {
9219       for (f = 0; f < dim; f++) {
9220         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9221       }
9222     }
9223     *detJ = J[0]*J[3] - J[1]*J[2];
9224     PetscLogFlops(8.0 + 3.0);
9225   }
9226   if (invJ) {
9227     const PetscReal invDet = 1.0/(*detJ);
9228 
9229     invJ[0] =  invDet*J[3];
9230     invJ[1] = -invDet*J[1];
9231     invJ[2] = -invDet*J[2];
9232     invJ[3] =  invDet*J[0];
9233     PetscLogFlops(5.0);
9234   }
9235   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9236   PetscFunctionReturn(0);
9237 }
9238 
9239 #undef __FUNCT__
9240 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9241 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9242 {
9243   PetscSection       coordSection;
9244   Vec                coordinates;
9245   const PetscScalar *coords;
9246   const PetscInt     dim = 3;
9247   PetscInt           d, f;
9248   PetscErrorCode     ierr;
9249 
9250   PetscFunctionBegin;
9251   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9252   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9253   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9254   if (v0) {
9255     for (d = 0; d < dim; d++) {
9256       v0[d] = PetscRealPart(coords[d]);
9257     }
9258   }
9259   if (J) {
9260     for (d = 0; d < dim; d++) {
9261       for (f = 0; f < dim; f++) {
9262         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9263       }
9264     }
9265     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9266     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9267              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9268              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9269     PetscLogFlops(18.0 + 12.0);
9270   }
9271   if (invJ) {
9272     const PetscReal invDet = 1.0/(*detJ);
9273 
9274     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9275     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9276     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9277     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9278     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9279     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9280     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9281     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9282     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9283     PetscLogFlops(37.0);
9284   }
9285   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9286   PetscFunctionReturn(0);
9287 }
9288 
9289 #undef __FUNCT__
9290 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9291 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9292 {
9293   PetscSection       coordSection;
9294   Vec                coordinates;
9295   const PetscScalar *coords;
9296   const PetscInt     dim = 3;
9297   PetscInt           d;
9298   PetscErrorCode     ierr;
9299 
9300   PetscFunctionBegin;
9301   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9302   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9303   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9304   if (v0) {
9305     for (d = 0; d < dim; d++) {
9306       v0[d] = PetscRealPart(coords[d]);
9307     }
9308   }
9309   if (J) {
9310     for (d = 0; d < dim; d++) {
9311       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9312       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9313       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9314     }
9315     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9316              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9317              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9318     PetscLogFlops(18.0 + 12.0);
9319   }
9320   if (invJ) {
9321     const PetscReal invDet = -1.0/(*detJ);
9322 
9323     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9324     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9325     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9326     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9327     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9328     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9329     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9330     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9331     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9332     PetscLogFlops(37.0);
9333   }
9334   *detJ *= 8.0;
9335   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9336   PetscFunctionReturn(0);
9337 }
9338 
9339 #undef __FUNCT__
9340 #define __FUNCT__ "DMPlexComputeCellGeometry"
9341 /*@C
9342   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9343 
9344   Collective on DM
9345 
9346   Input Arguments:
9347 + dm   - the DM
9348 - cell - the cell
9349 
9350   Output Arguments:
9351 + v0   - the translation part of this affine transform
9352 . J    - the Jacobian of the transform to the reference element
9353 . invJ - the inverse of the Jacobian
9354 - detJ - the Jacobian determinant
9355 
9356   Level: advanced
9357 
9358 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9359 @*/
9360 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9361 {
9362   PetscInt       dim, coneSize;
9363   PetscErrorCode ierr;
9364 
9365   PetscFunctionBegin;
9366   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9367   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9368   switch (dim) {
9369   case 2:
9370     switch (coneSize) {
9371     case 3:
9372       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9373       break;
9374     case 4:
9375       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9376       break;
9377     default:
9378       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9379     }
9380     break;
9381   case 3:
9382     switch (coneSize) {
9383     case 4:
9384       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9385       break;
9386     case 8:
9387       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9388       break;
9389     default:
9390       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9391     }
9392     break;
9393   default:
9394     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9395   }
9396   PetscFunctionReturn(0);
9397 }
9398 
9399 #undef __FUNCT__
9400 #define __FUNCT__ "DMPlexGetFaceOrientation"
9401 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9402 {
9403   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9404   PetscBool      posOrient = PETSC_FALSE;
9405   const PetscInt debug     = 0;
9406   PetscInt       cellDim, faceSize, f;
9407   PetscErrorCode ierr;
9408 
9409   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9410   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9411 
9412   if (cellDim == numCorners-1) {
9413     /* Simplices */
9414     faceSize  = numCorners-1;
9415     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9416   } else if (cellDim == 1 && numCorners == 3) {
9417     /* Quadratic line */
9418     faceSize  = 1;
9419     posOrient = PETSC_TRUE;
9420   } else if (cellDim == 2 && numCorners == 4) {
9421     /* Quads */
9422     faceSize  = 2;
9423     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9424       posOrient = PETSC_TRUE;
9425     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9426       posOrient = PETSC_TRUE;
9427     } else {
9428       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9429         posOrient = PETSC_FALSE;
9430       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9431     }
9432   } else if (cellDim == 2 && numCorners == 6) {
9433     /* Quadratic triangle (I hate this) */
9434     /* Edges are determined by the first 2 vertices (corners of edges) */
9435     const PetscInt faceSizeTri = 3;
9436     PetscInt  sortedIndices[3], i, iFace;
9437     PetscBool found = PETSC_FALSE;
9438     PetscInt  faceVerticesTriSorted[9] = {
9439       0, 3,  4, /* bottom */
9440       1, 4,  5, /* right */
9441       2, 3,  5, /* left */
9442     };
9443     PetscInt  faceVerticesTri[9] = {
9444       0, 3,  4, /* bottom */
9445       1, 4,  5, /* right */
9446       2, 5,  3, /* left */
9447     };
9448 
9449     faceSize = faceSizeTri;
9450     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9451     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9452     for (iFace = 0; iFace < 3; ++iFace) {
9453       const PetscInt ii = iFace*faceSizeTri;
9454       PetscInt       fVertex, cVertex;
9455 
9456       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9457           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9458         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9459           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9460             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9461               faceVertices[fVertex] = origVertices[cVertex];
9462               break;
9463             }
9464           }
9465         }
9466         found = PETSC_TRUE;
9467         break;
9468       }
9469     }
9470     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9471     if (posOriented) {*posOriented = PETSC_TRUE;}
9472     PetscFunctionReturn(0);
9473   } else if (cellDim == 2 && numCorners == 9) {
9474     /* Quadratic quad (I hate this) */
9475     /* Edges are determined by the first 2 vertices (corners of edges) */
9476     const PetscInt faceSizeQuad = 3;
9477     PetscInt  sortedIndices[3], i, iFace;
9478     PetscBool found = PETSC_FALSE;
9479     PetscInt  faceVerticesQuadSorted[12] = {
9480       0, 1,  4, /* bottom */
9481       1, 2,  5, /* right */
9482       2, 3,  6, /* top */
9483       0, 3,  7, /* left */
9484     };
9485     PetscInt  faceVerticesQuad[12] = {
9486       0, 1,  4, /* bottom */
9487       1, 2,  5, /* right */
9488       2, 3,  6, /* top */
9489       3, 0,  7, /* left */
9490     };
9491 
9492     faceSize = faceSizeQuad;
9493     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9494     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9495     for (iFace = 0; iFace < 4; ++iFace) {
9496       const PetscInt ii = iFace*faceSizeQuad;
9497       PetscInt       fVertex, cVertex;
9498 
9499       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9500           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9501         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9502           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9503             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9504               faceVertices[fVertex] = origVertices[cVertex];
9505               break;
9506             }
9507           }
9508         }
9509         found = PETSC_TRUE;
9510         break;
9511       }
9512     }
9513     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9514     if (posOriented) {*posOriented = PETSC_TRUE;}
9515     PetscFunctionReturn(0);
9516   } else if (cellDim == 3 && numCorners == 8) {
9517     /* Hexes
9518        A hex is two oriented quads with the normal of the first
9519        pointing up at the second.
9520 
9521           7---6
9522          /|  /|
9523         4---5 |
9524         | 3-|-2
9525         |/  |/
9526         0---1
9527 
9528         Faces are determined by the first 4 vertices (corners of faces) */
9529     const PetscInt faceSizeHex = 4;
9530     PetscInt  sortedIndices[4], i, iFace;
9531     PetscBool found = PETSC_FALSE;
9532     PetscInt faceVerticesHexSorted[24] = {
9533       0, 1, 2, 3,  /* bottom */
9534       4, 5, 6, 7,  /* top */
9535       0, 1, 4, 5,  /* front */
9536       1, 2, 5, 6,  /* right */
9537       2, 3, 6, 7,  /* back */
9538       0, 3, 4, 7,  /* left */
9539     };
9540     PetscInt faceVerticesHex[24] = {
9541       3, 2, 1, 0,  /* bottom */
9542       4, 5, 6, 7,  /* top */
9543       0, 1, 5, 4,  /* front */
9544       1, 2, 6, 5,  /* right */
9545       2, 3, 7, 6,  /* back */
9546       3, 0, 4, 7,  /* left */
9547     };
9548 
9549     faceSize = faceSizeHex;
9550     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9551     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9552     for (iFace = 0; iFace < 6; ++iFace) {
9553       const PetscInt ii = iFace*faceSizeHex;
9554       PetscInt       fVertex, cVertex;
9555 
9556       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9557           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9558           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9559           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9560         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9561           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9562             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9563               faceVertices[fVertex] = origVertices[cVertex];
9564               break;
9565             }
9566           }
9567         }
9568         found = PETSC_TRUE;
9569         break;
9570       }
9571     }
9572     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9573     if (posOriented) {*posOriented = PETSC_TRUE;}
9574     PetscFunctionReturn(0);
9575   } else if (cellDim == 3 && numCorners == 10) {
9576     /* Quadratic tet */
9577     /* Faces are determined by the first 3 vertices (corners of faces) */
9578     const PetscInt faceSizeTet = 6;
9579     PetscInt  sortedIndices[6], i, iFace;
9580     PetscBool found = PETSC_FALSE;
9581     PetscInt faceVerticesTetSorted[24] = {
9582       0, 1, 2,  6, 7, 8, /* bottom */
9583       0, 3, 4,  6, 7, 9,  /* front */
9584       1, 4, 5,  7, 8, 9,  /* right */
9585       2, 3, 5,  6, 8, 9,  /* left */
9586     };
9587     PetscInt faceVerticesTet[24] = {
9588       0, 1, 2,  6, 7, 8, /* bottom */
9589       0, 4, 3,  6, 7, 9,  /* front */
9590       1, 5, 4,  7, 8, 9,  /* right */
9591       2, 3, 5,  8, 6, 9,  /* left */
9592     };
9593 
9594     faceSize = faceSizeTet;
9595     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9596     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9597     for (iFace=0; iFace < 4; ++iFace) {
9598       const PetscInt ii = iFace*faceSizeTet;
9599       PetscInt       fVertex, cVertex;
9600 
9601       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9602           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9603           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9604           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9605         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9606           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9607             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9608               faceVertices[fVertex] = origVertices[cVertex];
9609               break;
9610             }
9611           }
9612         }
9613         found = PETSC_TRUE;
9614         break;
9615       }
9616     }
9617     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9618     if (posOriented) {*posOriented = PETSC_TRUE;}
9619     PetscFunctionReturn(0);
9620   } else if (cellDim == 3 && numCorners == 27) {
9621     /* Quadratic hexes (I hate this)
9622        A hex is two oriented quads with the normal of the first
9623        pointing up at the second.
9624 
9625          7---6
9626         /|  /|
9627        4---5 |
9628        | 3-|-2
9629        |/  |/
9630        0---1
9631 
9632        Faces are determined by the first 4 vertices (corners of faces) */
9633     const PetscInt faceSizeQuadHex = 9;
9634     PetscInt  sortedIndices[9], i, iFace;
9635     PetscBool found = PETSC_FALSE;
9636     PetscInt faceVerticesQuadHexSorted[54] = {
9637       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9638       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9639       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9640       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9641       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9642       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9643     };
9644     PetscInt faceVerticesQuadHex[54] = {
9645       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9646       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9647       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9648       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9649       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9650       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9651     };
9652 
9653     faceSize = faceSizeQuadHex;
9654     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9655     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9656     for (iFace = 0; iFace < 6; ++iFace) {
9657       const PetscInt ii = iFace*faceSizeQuadHex;
9658       PetscInt       fVertex, cVertex;
9659 
9660       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9661           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9662           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9663           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9664         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9665           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9666             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9667               faceVertices[fVertex] = origVertices[cVertex];
9668               break;
9669             }
9670           }
9671         }
9672         found = PETSC_TRUE;
9673         break;
9674       }
9675     }
9676     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9677     if (posOriented) {*posOriented = PETSC_TRUE;}
9678     PetscFunctionReturn(0);
9679   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9680   if (!posOrient) {
9681     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9682     for (f = 0; f < faceSize; ++f) {
9683       faceVertices[f] = origVertices[faceSize-1 - f];
9684     }
9685   } else {
9686     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9687     for (f = 0; f < faceSize; ++f) {
9688       faceVertices[f] = origVertices[f];
9689     }
9690   }
9691   if (posOriented) {*posOriented = posOrient;}
9692   PetscFunctionReturn(0);
9693 }
9694 
9695 #undef __FUNCT__
9696 #define __FUNCT__ "DMPlexGetOrientedFace"
9697 /*
9698     Given a cell and a face, as a set of vertices,
9699       return the oriented face, as a set of vertices, in faceVertices
9700     The orientation is such that the face normal points out of the cell
9701 */
9702 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9703 {
9704   const PetscInt *cone = PETSC_NULL;
9705   PetscInt        coneSize, v, f, v2;
9706   PetscInt        oppositeVertex = -1;
9707   PetscErrorCode  ierr;
9708 
9709   PetscFunctionBegin;
9710   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9711   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9712   for (v = 0, v2 = 0; v < coneSize; ++v) {
9713     PetscBool found  = PETSC_FALSE;
9714 
9715     for (f = 0; f < faceSize; ++f) {
9716       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9717     }
9718     if (found) {
9719       indices[v2]      = v;
9720       origVertices[v2] = cone[v];
9721       ++v2;
9722     } else {
9723       oppositeVertex = v;
9724     }
9725   }
9726   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9727   PetscFunctionReturn(0);
9728 }
9729 
9730 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9731 {
9732   switch (i) {
9733   case 0:
9734     switch (j) {
9735     case 0: return 0;
9736     case 1:
9737       switch (k) {
9738       case 0: return 0;
9739       case 1: return 0;
9740       case 2: return 1;
9741       }
9742     case 2:
9743       switch (k) {
9744       case 0: return 0;
9745       case 1: return -1;
9746       case 2: return 0;
9747       }
9748     }
9749   case 1:
9750     switch (j) {
9751     case 0:
9752       switch (k) {
9753       case 0: return 0;
9754       case 1: return 0;
9755       case 2: return -1;
9756       }
9757     case 1: return 0;
9758     case 2:
9759       switch (k) {
9760       case 0: return 1;
9761       case 1: return 0;
9762       case 2: return 0;
9763       }
9764     }
9765   case 2:
9766     switch (j) {
9767     case 0:
9768       switch (k) {
9769       case 0: return 0;
9770       case 1: return 1;
9771       case 2: return 0;
9772       }
9773     case 1:
9774       switch (k) {
9775       case 0: return -1;
9776       case 1: return 0;
9777       case 2: return 0;
9778       }
9779     case 2: return 0;
9780     }
9781   }
9782   return 0;
9783 }
9784 
9785 #undef __FUNCT__
9786 #define __FUNCT__ "DMPlexCreateRigidBody"
9787 /*@C
9788   DMPlexCreateRigidBody - create rigid body modes from coordinates
9789 
9790   Collective on DM
9791 
9792   Input Arguments:
9793 + dm - the DM
9794 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9795 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9796 
9797   Output Argument:
9798 . sp - the null space
9799 
9800   Note: This is necessary to take account of Dirichlet conditions on the displacements
9801 
9802   Level: advanced
9803 
9804 .seealso: MatNullSpaceCreate()
9805 @*/
9806 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9807 {
9808   MPI_Comm       comm = ((PetscObject) dm)->comm;
9809   Vec            coordinates, localMode, mode[6];
9810   PetscSection   coordSection;
9811   PetscScalar   *coords;
9812   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9813   PetscErrorCode ierr;
9814 
9815   PetscFunctionBegin;
9816   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9817   if (dim == 1) {
9818     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9819     PetscFunctionReturn(0);
9820   }
9821   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9822   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9823   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9824   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9825   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9826   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9827   m    = (dim*(dim+1))/2;
9828   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9829   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9830   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9831   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9832   /* Assume P1 */
9833   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9834   for (d = 0; d < dim; ++d) {
9835     PetscScalar values[3] = {0.0, 0.0, 0.0};
9836 
9837     values[d] = 1.0;
9838     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9839     for (v = vStart; v < vEnd; ++v) {
9840       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9841     }
9842     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9843     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9844   }
9845   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9846   for (d = dim; d < dim*(dim+1)/2; ++d) {
9847     PetscInt i, j, k = dim > 2 ? d - dim : d;
9848 
9849     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9850     for (v = vStart; v < vEnd; ++v) {
9851       PetscScalar values[3] = {0.0, 0.0, 0.0};
9852       PetscInt    off;
9853 
9854       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9855       for (i = 0; i < dim; ++i) {
9856         for (j = 0; j < dim; ++j) {
9857           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9858         }
9859       }
9860       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9861     }
9862     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9863     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9864   }
9865   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9866   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9867   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9868   /* Orthonormalize system */
9869   for (i = dim; i < m; ++i) {
9870     PetscScalar dots[6];
9871 
9872     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9873     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9874     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9875     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9876   }
9877   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9878   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9879   PetscFunctionReturn(0);
9880 }
9881 
9882 #undef __FUNCT__
9883 #define __FUNCT__ "DMPlexGetHybridBounds"
9884 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9885 {
9886   DM_Plex       *mesh = (DM_Plex *) dm->data;
9887   PetscInt       dim;
9888   PetscErrorCode ierr;
9889 
9890   PetscFunctionBegin;
9891   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9892   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9893   if (cMax) *cMax = mesh->hybridPointMax[dim];
9894   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9895   if (eMax) *eMax = mesh->hybridPointMax[1];
9896   if (vMax) *vMax = mesh->hybridPointMax[0];
9897   PetscFunctionReturn(0);
9898 }
9899 
9900 #undef __FUNCT__
9901 #define __FUNCT__ "DMPlexSetHybridBounds"
9902 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9903 {
9904   DM_Plex       *mesh = (DM_Plex *) dm->data;
9905   PetscInt       dim;
9906   PetscErrorCode ierr;
9907 
9908   PetscFunctionBegin;
9909   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9910   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9911   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9912   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9913   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9914   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9915   PetscFunctionReturn(0);
9916 }
9917 
9918 #undef __FUNCT__
9919 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9920 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9921 {
9922   DM_Plex *mesh = (DM_Plex *) dm->data;
9923 
9924   PetscFunctionBegin;
9925   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9926   PetscValidPointer(cellHeight, 2);
9927   *cellHeight = mesh->vtkCellHeight;
9928   PetscFunctionReturn(0);
9929 }
9930 
9931 #undef __FUNCT__
9932 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9933 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9934 {
9935   DM_Plex *mesh = (DM_Plex *) dm->data;
9936 
9937   PetscFunctionBegin;
9938   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9939   mesh->vtkCellHeight = cellHeight;
9940   PetscFunctionReturn(0);
9941 }
9942 
9943 #undef __FUNCT__
9944 #define __FUNCT__ "DMPlexInsertFace_Private"
9945 /*
9946   DMPlexInsertFace_Private - Puts a face into the mesh
9947 
9948   Not collective
9949 
9950   Input Parameters:
9951   + dm              - The DMPlex
9952   . numFaceVertex   - The number of vertices in the face
9953   . faceVertices    - The vertices in the face for dm
9954   . subfaceVertices - The vertices in the face for subdm
9955   . numCorners      - The number of vertices in the cell
9956   . cell            - A cell in dm containing the face
9957   . subcell         - A cell in subdm containing the face
9958   . firstFace       - First face in the mesh
9959   - newFacePoint    - Next face in the mesh
9960 
9961   Output Parameters:
9962   . newFacePoint - Contains next face point number on input, updated on output
9963 
9964   Level: developer
9965 */
9966 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)
9967 {
9968   MPI_Comm        comm    = ((PetscObject) dm)->comm;
9969   DM_Plex     *submesh = (DM_Plex *) subdm->data;
9970   const PetscInt *faces;
9971   PetscInt        numFaces, coneSize;
9972   PetscErrorCode  ierr;
9973 
9974   PetscFunctionBegin;
9975   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
9976   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
9977 #if 0
9978   /* Cannot use this because support() has not been constructed yet */
9979   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
9980 #else
9981   {
9982     PetscInt f;
9983 
9984     numFaces = 0;
9985     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
9986     for (f = firstFace; f < *newFacePoint; ++f) {
9987       PetscInt dof, off, d;
9988 
9989       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
9990       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
9991       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
9992       for (d = 0; d < dof; ++d) {
9993         const PetscInt p = submesh->cones[off+d];
9994         PetscInt       v;
9995 
9996         for (v = 0; v < numFaceVertices; ++v) {
9997           if (subfaceVertices[v] == p) break;
9998         }
9999         if (v == numFaceVertices) break;
10000       }
10001       if (d == dof) {
10002         numFaces = 1;
10003         ((PetscInt *) faces)[0] = f;
10004       }
10005     }
10006   }
10007 #endif
10008   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
10009   else if (numFaces == 1) {
10010     /* Add the other cell neighbor for this face */
10011     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
10012   } else {
10013     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
10014     PetscBool posOriented;
10015 
10016     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10017     origVertices = &orientedVertices[numFaceVertices];
10018     indices      = &orientedVertices[numFaceVertices*2];
10019     orientedSubVertices = &orientedVertices[numFaceVertices*3];
10020     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
10021     /* TODO: I know that routine should return a permutation, not the indices */
10022     for (v = 0; v < numFaceVertices; ++v) {
10023       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
10024       for (ov = 0; ov < numFaceVertices; ++ov) {
10025         if (orientedVertices[ov] == vertex) {
10026           orientedSubVertices[ov] = subvertex;
10027           break;
10028         }
10029       }
10030       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
10031     }
10032     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
10033     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
10034     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10035     ++(*newFacePoint);
10036   }
10037   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10038   PetscFunctionReturn(0);
10039 }
10040 
10041 #undef __FUNCT__
10042 #define __FUNCT__ "DMPlexCreateSubmesh"
10043 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
10044 {
10045   MPI_Comm        comm = ((PetscObject) dm)->comm;
10046   DM_Plex     *submesh;
10047   PetscBool       boundaryFaces = PETSC_FALSE;
10048   PetscSection    coordSection, subCoordSection;
10049   Vec             coordinates, subCoordinates;
10050   PetscScalar    *coords, *subCoords;
10051   IS              labelIS;
10052   const PetscInt *subVertices;
10053   PetscInt       *subVerticesActive, *tmpPoints;
10054   PetscInt       *subCells = PETSC_NULL;
10055   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
10056   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
10057   PetscInt        dim; /* Right now, do not specify dimension */
10058   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
10059   PetscErrorCode  ierr;
10060 
10061   PetscFunctionBegin;
10062   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10063   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10064   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10065   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
10066   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10067   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10068   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10069   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10070   subface = &face[maxConeSize];
10071   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
10072   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10073   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10074   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
10075   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
10076   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
10077   maxSubCells = numSubVertices;
10078   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
10079   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
10080   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
10081   for (v = 0; v < numSubVertices; ++v) {
10082     const PetscInt vertex = subVertices[v];
10083     PetscInt *star = PETSC_NULL;
10084     PetscInt  starSize, numCells = 0;
10085 
10086     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10087     for (p = 0; p < starSize*2; p += 2) {
10088       const PetscInt point = star[p];
10089       if ((point >= cStart) && (point < cEnd)) {
10090         star[numCells++] = point;
10091       }
10092     }
10093     numOldSubCells = numSubCells;
10094     for (c = 0; c < numCells; ++c) {
10095       const PetscInt cell    = star[c];
10096       PetscInt      *closure = PETSC_NULL;
10097       PetscInt       closureSize, numCorners = 0, faceSize = 0;
10098       PetscInt       cellLoc;
10099 
10100       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
10101       if (cellLoc >= 0) continue;
10102       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10103       for (p = 0; p < closureSize*2; p += 2) {
10104         const PetscInt point = closure[p];
10105         if ((point >= vStart) && (point < vEnd)) {
10106           closure[numCorners++] = point;
10107         }
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) {if (cellVertex == face[i]) break;}
10117           if (i == faceSize) {
10118             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
10119             face[faceSize]    = cellVertex;
10120             subface[faceSize] = subVertex;
10121             ++faceSize;
10122           }
10123         }
10124       }
10125       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10126       if (faceSize >= nFV) {
10127         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10128         if (numSubCells >= maxSubCells) {
10129           PetscInt *tmpCells;
10130           maxSubCells *= 2;
10131           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
10132           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
10133           ierr = PetscFree(subCells);CHKERRQ(ierr);
10134           subCells = tmpCells;
10135         }
10136         /* TOOD: Maybe overestimate then squeeze out empty faces */
10137         if (faceSize > nFV) {
10138           /* TODO: This is tricky. Maybe just add all faces */
10139           numSubFaces++;
10140         } else {
10141           numSubFaces++;
10142         }
10143         for (f = 0; f < faceSize; ++f) {
10144           subVerticesActive[subface[f]] = 1;
10145         }
10146         subCells[numSubCells++] = cell;
10147       }
10148     }
10149     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10150     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
10151   }
10152   /* Pick out active subvertices */
10153   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
10154     if (subVerticesActive[v]) {
10155       subVerticesActive[numSubVerticesActive++] = subVertices[v];
10156     }
10157   }
10158   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
10159   /* Set cone sizes */
10160   firstSubVertex = numSubCells;
10161   firstSubFace   = numSubCells+numSubVerticesActive;
10162   newFacePoint   = firstSubFace;
10163   for (c = 0; c < numSubCells; ++c) {
10164     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
10165   }
10166   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
10167     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
10168   }
10169   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
10170   /* Create face cones */
10171   for (c = 0; c < numSubCells; ++c) {
10172     const PetscInt cell    = subCells[c];
10173     PetscInt      *closure = PETSC_NULL;
10174     PetscInt       closureSize, numCorners = 0, faceSize = 0;
10175 
10176     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10177     for (p = 0; p < closureSize*2; p += 2) {
10178       const PetscInt point = closure[p];
10179       if ((point >= vStart) && (point < vEnd)) {
10180         closure[numCorners++] = point;
10181       }
10182     }
10183     for (corner = 0; corner < numCorners; ++corner) {
10184       const PetscInt cellVertex = closure[corner];
10185       PetscInt       subVertex;
10186 
10187       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
10188       if (subVertex >= 0) { /* contains submesh vertex */
10189         for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10190         if (i == faceSize) {
10191           face[faceSize]    = cellVertex;
10192           subface[faceSize] = numSubCells+subVertex;
10193           ++faceSize;
10194         }
10195       }
10196     }
10197     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10198     if (faceSize >= nFV) {
10199       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10200       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
10201       /*   We have to take all the faces, and discard those in the interior */
10202       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
10203 #if 0
10204       /* This object just calls insert on each face that comes from subsets() */
10205       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
10206       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
10207       PointArray                          faceVec(face->begin(), face->end());
10208 
10209       subsets(faceVec, nFV, inserter);
10210 #endif
10211       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10212     }
10213   }
10214   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
10215   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
10216   /* Build coordinates */
10217   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10218   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10219   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
10220   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10221   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10222     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10223   }
10224   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10225   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10226   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
10227   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10228   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10229   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10230   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10231   for (v = 0; v < numSubVerticesActive; ++v) {
10232     const PetscInt vertex    = subVerticesActive[v];
10233     const PetscInt subVertex = firstSubVertex+v;
10234     PetscInt dof, off, sdof, soff;
10235 
10236     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10237     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10238     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10239     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10240     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10241     for (d = 0; d < dof; ++d) {
10242       subCoords[soff+d] = coords[off+d];
10243     }
10244   }
10245   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10246   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10247   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
10248   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10249 
10250   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
10251   /* Create map from submesh points to original mesh points */
10252   submesh = (DM_Plex *) (*subdm)->data;
10253   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10254   for (c = 0; c < numSubCells; ++c) {
10255     tmpPoints[c] = subCells[c];
10256   }
10257   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
10258     tmpPoints[v] = subVerticesActive[v-numSubCells];
10259   }
10260   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
10261 
10262   ierr = PetscFree(subCells);CHKERRQ(ierr);
10263   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10264   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10265   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10266   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10267   PetscFunctionReturn(0);
10268 }
10269 
10270 #undef __FUNCT__
10271 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10272 /* We can easily have a form that takes an IS instead */
10273 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10274 {
10275   PetscSection   section, globalSection;
10276   PetscInt      *numbers, p;
10277   PetscErrorCode ierr;
10278 
10279   PetscFunctionBegin;
10280   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10281   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10282   for (p = pStart; p < pEnd; ++p) {
10283     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10284   }
10285   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10286   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10287   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10288   for (p = pStart; p < pEnd; ++p) {
10289     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10290   }
10291   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10292   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10293   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10294   PetscFunctionReturn(0);
10295 }
10296 
10297 #undef __FUNCT__
10298 #define __FUNCT__ "DMPlexGetCellNumbering"
10299 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10300 {
10301   DM_Plex    *mesh = (DM_Plex *) dm->data;
10302   PetscInt       cellHeight, cStart, cEnd, cMax;
10303   PetscErrorCode ierr;
10304 
10305   PetscFunctionBegin;
10306   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10307   if (!mesh->globalCellNumbers) {
10308     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10309     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10310     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10311     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10312     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10313   }
10314   *globalCellNumbers = mesh->globalCellNumbers;
10315   PetscFunctionReturn(0);
10316 }
10317 
10318 #undef __FUNCT__
10319 #define __FUNCT__ "DMPlexGetVertexNumbering"
10320 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10321 {
10322   DM_Plex    *mesh = (DM_Plex *) dm->data;
10323   PetscInt       vStart, vEnd, vMax;
10324   PetscErrorCode ierr;
10325 
10326   PetscFunctionBegin;
10327   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10328   if (!mesh->globalVertexNumbers) {
10329     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10330     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10331     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10332     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10333   }
10334   *globalVertexNumbers = mesh->globalVertexNumbers;
10335   PetscFunctionReturn(0);
10336 }
10337 
10338 #undef __FUNCT__
10339 #define __FUNCT__ "DMPlexGetSubpointMap"
10340 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10341 {
10342   DM_Plex *mesh = (DM_Plex *) dm->data;
10343 
10344   PetscFunctionBegin;
10345   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10346   PetscValidPointer(subpointMap, 2);
10347   *subpointMap = mesh->subpointMap;
10348   PetscFunctionReturn(0);
10349 }
10350 
10351 #undef __FUNCT__
10352 #define __FUNCT__ "DMPlexSetSubpointMap"
10353 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10354 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10355 {
10356   DM_Plex *mesh = (DM_Plex *) dm->data;
10357 
10358   PetscFunctionBegin;
10359   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10360   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10361   mesh->subpointMap = subpointMap;
10362   PetscFunctionReturn(0);
10363 }
10364 
10365 #undef __FUNCT__
10366 #define __FUNCT__ "DMPlexGetScale"
10367 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10368 {
10369   DM_Plex *mesh = (DM_Plex *) dm->data;
10370 
10371   PetscFunctionBegin;
10372   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10373   PetscValidPointer(scale, 3);
10374   *scale = mesh->scale[unit];
10375   PetscFunctionReturn(0);
10376 }
10377 
10378 #undef __FUNCT__
10379 #define __FUNCT__ "DMPlexSetScale"
10380 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10381 {
10382   DM_Plex *mesh = (DM_Plex *) dm->data;
10383 
10384   PetscFunctionBegin;
10385   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10386   mesh->scale[unit] = scale;
10387   PetscFunctionReturn(0);
10388 }
10389 
10390 
10391 /*******************************************************************************
10392 This should be in a separate Discretization object, but I am not sure how to lay
10393 it out yet, so I am stuffing things here while I experiment.
10394 *******************************************************************************/
10395 #undef __FUNCT__
10396 #define __FUNCT__ "DMPlexSetFEMIntegration"
10397 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10398                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10399                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10400                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10401                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10402                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10403                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10404                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10405                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10406                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10407                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10408                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10409                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10410                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10411                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10412                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10413                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10414 {
10415   DM_Plex *mesh = (DM_Plex *) dm->data;
10416 
10417   PetscFunctionBegin;
10418   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10419   mesh->integrateResidualFEM       = integrateResidualFEM;
10420   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10421   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10422   PetscFunctionReturn(0);
10423 }
10424 
10425 #undef __FUNCT__
10426 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10427 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10428 {
10429   Vec            coordinates;
10430   PetscSection   section, cSection;
10431   PetscInt       dim, vStart, vEnd, v, c, d;
10432   PetscScalar   *values, *cArray;
10433   PetscReal     *coords;
10434   PetscErrorCode ierr;
10435 
10436   PetscFunctionBegin;
10437   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10438   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10439   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10440   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10441   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10442   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10443   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10444   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10445   for (v = vStart; v < vEnd; ++v) {
10446     PetscInt dof, off;
10447 
10448     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10449     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10450     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10451     for (d = 0; d < dof; ++d) {
10452       coords[d] = PetscRealPart(cArray[off+d]);
10453     }
10454     for (c = 0; c < numComp; ++c) {
10455       values[c] = (*funcs[c])(coords);
10456     }
10457     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10458   }
10459   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10460   /* Temporary, must be replaced by a projection on the finite element basis */
10461   {
10462     PetscInt eStart = 0, eEnd = 0, e, depth;
10463 
10464     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10465     --depth;
10466     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10467     for (e = eStart; e < eEnd; ++e) {
10468       const PetscInt *cone = PETSC_NULL;
10469       PetscInt        coneSize, d;
10470       PetscScalar    *coordsA, *coordsB;
10471 
10472       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10473       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10474       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10475       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10476       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10477       for (d = 0; d < dim; ++d) {
10478         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10479       }
10480       for (c = 0; c < numComp; ++c) {
10481         values[c] = (*funcs[c])(coords);
10482       }
10483       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10484     }
10485   }
10486 
10487   ierr = PetscFree(coords);CHKERRQ(ierr);
10488   ierr = PetscFree(values);CHKERRQ(ierr);
10489 #if 0
10490   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10491   PetscReal      detJ;
10492 
10493   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10494   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10495   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10496 
10497   for (PetscInt c = cStart; c < cEnd; ++c) {
10498     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10499     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10500     const int                          oSize   = pV.getSize();
10501     int                                v       = 0;
10502 
10503     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10504     for (PetscInt cl = 0; cl < oSize; ++cl) {
10505       const PetscInt fDim;
10506 
10507       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10508       if (pointDim) {
10509         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10510           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10511         }
10512       }
10513     }
10514     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10515     pV.clear();
10516   }
10517   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10518   ierr = PetscFree(values);CHKERRQ(ierr);
10519 #endif
10520   PetscFunctionReturn(0);
10521 }
10522 
10523 #undef __FUNCT__
10524 #define __FUNCT__ "DMPlexProjectFunction"
10525 /*@C
10526   DMPlexProjectFunction - This projects the given function into the function space provided.
10527 
10528   Input Parameters:
10529 + dm      - The DM
10530 . numComp - The number of components (functions)
10531 . funcs   - The coordinate functions to evaluate
10532 - mode    - The insertion mode for values
10533 
10534   Output Parameter:
10535 . X - vector
10536 
10537   Level: developer
10538 
10539   Note:
10540   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10541   We will eventually fix it.
10542 
10543 ,seealso: DMPlexComputeL2Diff()
10544 */
10545 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10546 {
10547   Vec            localX;
10548   PetscErrorCode ierr;
10549 
10550   PetscFunctionBegin;
10551   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10552   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10553   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10554   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10555   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10556   PetscFunctionReturn(0);
10557 }
10558 
10559 #undef __FUNCT__
10560 #define __FUNCT__ "DMPlexComputeL2Diff"
10561 /*@C
10562   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10563 
10564   Input Parameters:
10565 + dm    - The DM
10566 . quad  - The PetscQuadrature object for each field
10567 . funcs - The functions to evaluate for each field component
10568 - X     - The coefficient vector u_h
10569 
10570   Output Parameter:
10571 . diff - The diff ||u - u_h||_2
10572 
10573   Level: developer
10574 
10575 .seealso: DMPlexProjectFunction()
10576 */
10577 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10578 {
10579   const PetscInt   debug = 0;
10580   PetscSection     section;
10581   Vec              localX;
10582   PetscReal       *coords, *v0, *J, *invJ, detJ;
10583   PetscReal        localDiff = 0.0;
10584   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10585   PetscErrorCode   ierr;
10586 
10587   PetscFunctionBegin;
10588   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10589   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10590   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10591   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10592   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10593   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10594   for (field = 0; field < numFields; ++field) {
10595     numComponents += quad[field].numComponents;
10596   }
10597   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10598   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10599   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10600   for (c = cStart; c < cEnd; ++c) {
10601     const PetscScalar *x;
10602     PetscReal          elemDiff = 0.0;
10603 
10604     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10605     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10606     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10607 
10608     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10609       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10610       const PetscReal *quadPoints    = quad[field].quadPoints;
10611       const PetscReal *quadWeights   = quad[field].quadWeights;
10612       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10613       const PetscInt   numBasisComps = quad[field].numComponents;
10614       const PetscReal *basis         = quad[field].basis;
10615       PetscInt         q, d, e, fc, f;
10616 
10617       if (debug) {
10618         char title[1024];
10619         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10620         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10621       }
10622       for (q = 0; q < numQuadPoints; ++q) {
10623         for (d = 0; d < dim; d++) {
10624           coords[d] = v0[d];
10625           for (e = 0; e < dim; e++) {
10626             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10627           }
10628         }
10629         for (fc = 0; fc < numBasisComps; ++fc) {
10630           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10631           PetscReal       interpolant = 0.0;
10632           for (f = 0; f < numBasisFuncs; ++f) {
10633             const PetscInt fidx = f*numBasisComps+fc;
10634             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10635           }
10636           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10637           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10638         }
10639       }
10640       comp        += numBasisComps;
10641       fieldOffset += numBasisFuncs*numBasisComps;
10642     }
10643     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10644     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10645     localDiff += elemDiff;
10646   }
10647   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10648   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10649   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10650   *diff = PetscSqrtReal(*diff);
10651   PetscFunctionReturn(0);
10652 }
10653 
10654 #undef __FUNCT__
10655 #define __FUNCT__ "DMPlexComputeResidualFEM"
10656 /*@
10657   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10658 
10659   Input Parameters:
10660 + dm - The mesh
10661 . X  - Local input vector
10662 - user - The user context
10663 
10664   Output Parameter:
10665 . F  - Local output vector
10666 
10667   Note:
10668   The second member of the user context must be an FEMContext.
10669 
10670   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10671   like a GPU, or vectorize on a multicore machine.
10672 
10673 .seealso: DMPlexComputeJacobianActionFEM()
10674 */
10675 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10676 {
10677   DM_Plex      *mesh = (DM_Plex *) dm->data;
10678   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10679   PetscQuadrature *quad = fem->quad;
10680   PetscSection     section;
10681   PetscReal       *v0, *J, *invJ, *detJ;
10682   PetscScalar     *elemVec, *u;
10683   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10684   PetscInt         cellDof = 0, numComponents = 0;
10685   PetscErrorCode   ierr;
10686 
10687   PetscFunctionBegin;
10688   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10689   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10690   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10691   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10692   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10693   numCells = cEnd - cStart;
10694   for (field = 0; field < numFields; ++field) {
10695     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10696     numComponents += quad[field].numComponents;
10697   }
10698   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10699   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10700   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);
10701   for (c = cStart; c < cEnd; ++c) {
10702     const PetscScalar *x;
10703     PetscInt           i;
10704 
10705     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10706     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10707     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10708 
10709     for (i = 0; i < cellDof; ++i) {
10710       u[c*cellDof+i] = x[i];
10711     }
10712     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10713   }
10714   for (field = 0; field < numFields; ++field) {
10715     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10716     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10717     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10718     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10719     /* Conforming batches */
10720     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10721     PetscInt numBlocks  = 1;
10722     PetscInt batchSize  = numBlocks * blockSize;
10723     PetscInt numBatches = numBatchesTmp;
10724     PetscInt numChunks  = numCells / (numBatches*batchSize);
10725     /* Remainder */
10726     PetscInt numRemainder = numCells % (numBatches * batchSize);
10727     PetscInt offset       = numCells - numRemainder;
10728 
10729     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10730     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10731                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10732   }
10733   for (c = cStart; c < cEnd; ++c) {
10734     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10735     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10736   }
10737   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10738   if (mesh->printFEM) {
10739     PetscMPIInt rank, numProcs;
10740     PetscInt    p;
10741 
10742     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10743     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10744     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10745     for (p = 0; p < numProcs; ++p) {
10746       if (p == rank) {
10747         Vec f;
10748 
10749         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10750         ierr = VecCopy(F, f);CHKERRQ(ierr);
10751         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10752         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10753         ierr = VecDestroy(&f);CHKERRQ(ierr);
10754         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10755       }
10756       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10757     }
10758   }
10759   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10760   PetscFunctionReturn(0);
10761 }
10762 
10763 #undef __FUNCT__
10764 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10765 /*@C
10766   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10767 
10768   Input Parameters:
10769 + dm - The mesh
10770 . J  - The Jacobian shell matrix
10771 . X  - Local input vector
10772 - user - The user context
10773 
10774   Output Parameter:
10775 . F  - Local output vector
10776 
10777   Note:
10778   The second member of the user context must be an FEMContext.
10779 
10780   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10781   like a GPU, or vectorize on a multicore machine.
10782 
10783 .seealso: DMPlexComputeResidualFEM()
10784 */
10785 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10786 {
10787   DM_Plex      *mesh = (DM_Plex *) dm->data;
10788   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10789   PetscQuadrature *quad = fem->quad;
10790   PetscSection     section;
10791   JacActionCtx    *jctx;
10792   PetscReal       *v0, *J, *invJ, *detJ;
10793   PetscScalar     *elemVec, *u, *a;
10794   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10795   PetscInt         cellDof = 0;
10796   PetscErrorCode   ierr;
10797 
10798   PetscFunctionBegin;
10799   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10800   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10801   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10802   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10803   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10804   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10805   numCells = cEnd - cStart;
10806   for (field = 0; field < numFields; ++field) {
10807     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10808   }
10809   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10810   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);
10811   for (c = cStart; c < cEnd; ++c) {
10812     const PetscScalar *x;
10813     PetscInt           i;
10814 
10815     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10816     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10817     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10818     for (i = 0; i < cellDof; ++i) {
10819       u[c*cellDof+i] = x[i];
10820     }
10821     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10822     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10823     for (i = 0; i < cellDof; ++i) {
10824       a[c*cellDof+i] = x[i];
10825     }
10826     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10827   }
10828   for (field = 0; field < numFields; ++field) {
10829     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10830     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10831     /* Conforming batches */
10832     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10833     PetscInt numBlocks  = 1;
10834     PetscInt batchSize  = numBlocks * blockSize;
10835     PetscInt numBatches = numBatchesTmp;
10836     PetscInt numChunks  = numCells / (numBatches*batchSize);
10837     /* Remainder */
10838     PetscInt numRemainder = numCells % (numBatches * batchSize);
10839     PetscInt offset       = numCells - numRemainder;
10840 
10841     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);
10842     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],
10843                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10844   }
10845   for (c = cStart; c < cEnd; ++c) {
10846     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10847     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10848   }
10849   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10850   if (mesh->printFEM) {
10851     PetscMPIInt rank, numProcs;
10852     PetscInt    p;
10853 
10854     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10855     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10856     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10857     for (p = 0; p < numProcs; ++p) {
10858       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10859       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10860     }
10861   }
10862   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10863   PetscFunctionReturn(0);
10864 }
10865 
10866 #undef __FUNCT__
10867 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10868 /*@
10869   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10870 
10871   Input Parameters:
10872 + dm - The mesh
10873 . X  - Local input vector
10874 - user - The user context
10875 
10876   Output Parameter:
10877 . Jac  - Jacobian matrix
10878 
10879   Note:
10880   The second member of the user context must be an FEMContext.
10881 
10882   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10883   like a GPU, or vectorize on a multicore machine.
10884 
10885 .seealso: FormFunctionLocal()
10886 */
10887 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10888 {
10889   DM_Plex      *mesh = (DM_Plex *) dm->data;
10890   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10891   PetscQuadrature *quad = fem->quad;
10892   PetscSection     section;
10893   PetscReal       *v0, *J, *invJ, *detJ;
10894   PetscScalar     *elemMat, *u;
10895   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10896   PetscInt         cellDof = 0, numComponents = 0;
10897   PetscBool        isShell;
10898   PetscErrorCode   ierr;
10899 
10900   PetscFunctionBegin;
10901   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10902   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10903   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10904   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10905   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10906   numCells = cEnd - cStart;
10907   for (field = 0; field < numFields; ++field) {
10908     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10909     numComponents += quad[field].numComponents;
10910   }
10911   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10912   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10913   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);
10914   for (c = cStart; c < cEnd; ++c) {
10915     const PetscScalar *x;
10916     PetscInt           i;
10917 
10918     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10919     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10920     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10921 
10922     for (i = 0; i < cellDof; ++i) {
10923       u[c*cellDof+i] = x[i];
10924     }
10925     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10926   }
10927   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10928   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10929     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10930     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10931     PetscInt       fieldJ;
10932 
10933     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10934       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10935       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10936       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10937       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10938       /* Conforming batches */
10939       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10940       PetscInt numBlocks  = 1;
10941       PetscInt batchSize  = numBlocks * blockSize;
10942       PetscInt numBatches = numBatchesTmp;
10943       PetscInt numChunks  = numCells / (numBatches*batchSize);
10944       /* Remainder */
10945       PetscInt numRemainder = numCells % (numBatches * batchSize);
10946       PetscInt offset       = numCells - numRemainder;
10947 
10948       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10949       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10950                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
10951     }
10952   }
10953   for (c = cStart; c < cEnd; ++c) {
10954     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
10955     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
10956   }
10957   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
10958 
10959   /* Assemble matrix, using the 2-step process:
10960        MatAssemblyBegin(), MatAssemblyEnd(). */
10961   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10962   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
10963 
10964   if (mesh->printFEM) {
10965     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
10966     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
10967     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
10968   }
10969   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10970   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
10971   if (isShell) {
10972     JacActionCtx *jctx;
10973 
10974     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10975     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
10976   }
10977   *str = SAME_NONZERO_PATTERN;
10978   PetscFunctionReturn(0);
10979 }
10980 
10981 
10982 #undef __FUNCT__
10983 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
10984 /*@C
10985   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
10986   the local section and an SF describing the section point overlap.
10987 
10988   Input Parameters:
10989   + s - The PetscSection for the local field layout
10990   . sf - The SF describing parallel layout of the section points
10991   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
10992   . label - The label specifying the points
10993   - labelValue - The label stratum specifying the points
10994 
10995   Output Parameter:
10996   . gsection - The PetscSection for the global field layout
10997 
10998   Note: This gives negative sizes and offsets to points not owned by this process
10999 
11000   Level: developer
11001 
11002 .seealso: PetscSectionCreate()
11003 @*/
11004 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
11005 {
11006   PetscInt      *neg;
11007   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
11008   PetscErrorCode ierr;
11009 
11010   PetscFunctionBegin;
11011   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
11012   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
11013   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
11014   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
11015   /* Mark ghost points with negative dof */
11016   for (p = pStart; p < pEnd; ++p) {
11017     PetscInt value;
11018 
11019     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11020     if (value != labelValue) continue;
11021     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11022     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11023     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11024     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11025     neg[p-pStart] = -(dof+1);
11026   }
11027   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11028   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11029   if (nroots >= 0) {
11030     if (nroots > pEnd - pStart) {
11031       PetscInt *tmpDof;
11032       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11033       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11034       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11035       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11036       for (p = pStart; p < pEnd; ++p) {
11037         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
11038       }
11039       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11040     } else {
11041       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11042       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11043     }
11044   }
11045   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11046   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11047     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11048     (*gsection)->atlasOff[p] = off;
11049     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11050   }
11051   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11052   globalOff -= off;
11053   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11054     (*gsection)->atlasOff[p] += globalOff;
11055     neg[p] = -((*gsection)->atlasOff[p]+1);
11056   }
11057   /* Put in negative offsets for ghost points */
11058   if (nroots >= 0) {
11059     if (nroots > pEnd - pStart) {
11060       PetscInt *tmpOff;
11061       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11062       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11063       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11064       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11065       for (p = pStart; p < pEnd; ++p) {
11066         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
11067       }
11068       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11069     } else {
11070       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11071       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11072     }
11073   }
11074   ierr = PetscFree(neg);CHKERRQ(ierr);
11075   PetscFunctionReturn(0);
11076 }
11077