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