xref: /petsc/src/dm/impls/plex/plex.c (revision 4dc2109ab1ff089d911ad1136a310d26c5230baf)
1 #include <petsc-private/pleximpl.h>   /*I      "petscdmplex.h"   I*/
2 #include <../src/sys/utils/hash.h>
3 
4 /* Logging support */
5 PetscLogEvent DMPLEX_Distribute, DMPLEX_Stratify;
6 
7 extern PetscErrorCode VecView_Seq(Vec, PetscViewer);
8 extern PetscErrorCode VecView_MPI(Vec, PetscViewer);
9 
10 #undef __FUNCT__
11 #define __FUNCT__ "VecView_Plex_Local"
12 PetscErrorCode VecView_Plex_Local(Vec v, PetscViewer viewer)
13 {
14   DM             dm;
15   PetscBool      isvtk;
16   PetscErrorCode ierr;
17 
18   PetscFunctionBegin;
19   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
20   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
21   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
22   if (isvtk) {
23     PetscViewerVTKFieldType ft = PETSC_VTK_POINT_FIELD;
24     PetscSection            section;
25     PetscInt                dim, pStart, pEnd, cStart, fStart, vStart, cdof = 0, fdof = 0, vdof = 0;
26 
27     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
28     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
29     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
30     ierr = DMPlexGetHeightStratum(dm, 1, &fStart, PETSC_NULL);CHKERRQ(ierr);
31     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, PETSC_NULL);CHKERRQ(ierr);
32     ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
33     /* Assumes that numer of dofs per point of each stratum is constant, natural for VTK */
34     if ((cStart >= pStart) && (cStart < pEnd)) {ierr = PetscSectionGetDof(section, cStart, &cdof);CHKERRQ(ierr);}
35     if ((fStart >= pStart) && (fStart < pEnd)) {ierr = PetscSectionGetDof(section, fStart, &fdof);CHKERRQ(ierr);}
36     if ((vStart >= pStart) && (vStart < pEnd)) {ierr = PetscSectionGetDof(section, vStart, &vdof);CHKERRQ(ierr);}
37     if (cdof && fdof && vdof) { /* Actually Q2 or some such, but visualize as Q1 */
38       ft = (cdof == dim) ? PETSC_VTK_POINT_VECTOR_FIELD : PETSC_VTK_POINT_FIELD;
39     } else if (cdof && vdof) {
40       SETERRQ(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"No support for viewing mixed space with dofs at both vertices and cells");
41     } else if (cdof) {
42       /* TODO: This assumption should be removed when there is a way of identifying whether a space is conceptually a
43        * vector or just happens to have the same number of dofs as the dimension. */
44       if (cdof == dim) {
45         ft = PETSC_VTK_CELL_VECTOR_FIELD;
46       } else {
47         ft = PETSC_VTK_CELL_FIELD;
48       }
49     } else if (vdof) {
50       if (vdof == dim) {
51         ft = PETSC_VTK_POINT_VECTOR_FIELD;
52       } else {
53         ft = PETSC_VTK_POINT_FIELD;
54       }
55     } else SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Could not classify input Vec for VTK");
56 
57     ierr = PetscObjectReference((PetscObject) dm);CHKERRQ(ierr); /* viewer drops reference */
58     ierr = PetscObjectReference((PetscObject) v);CHKERRQ(ierr);  /* viewer drops reference */
59     ierr = PetscViewerVTKAddField(viewer, (PetscObject) dm, DMPlexVTKWriteAll, ft, (PetscObject) v);CHKERRQ(ierr);
60   } else {
61     PetscBool isseq;
62 
63     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
64     if (isseq) {
65       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
66     } else {
67       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
68     }
69   }
70   PetscFunctionReturn(0);
71 }
72 
73 #undef __FUNCT__
74 #define __FUNCT__ "VecView_Plex"
75 PetscErrorCode VecView_Plex(Vec v, PetscViewer viewer)
76 {
77   DM             dm;
78   PetscBool      isvtk;
79   PetscErrorCode ierr;
80 
81   PetscFunctionBegin;
82   ierr = VecGetDM(v, &dm);CHKERRQ(ierr);
83   if (!dm) SETERRQ(((PetscObject) v)->comm, PETSC_ERR_ARG_WRONG, "Vector not generated from a DM");
84   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
85   if (isvtk) {
86     Vec         locv;
87     const char *name;
88 
89     ierr = DMGetLocalVector(dm, &locv);CHKERRQ(ierr);
90     ierr = PetscObjectGetName((PetscObject) v, &name);CHKERRQ(ierr);
91     ierr = PetscObjectSetName((PetscObject) locv, name);CHKERRQ(ierr);
92     ierr = DMGlobalToLocalBegin(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
93     ierr = DMGlobalToLocalEnd(dm, v, INSERT_VALUES, locv);CHKERRQ(ierr);
94     ierr = VecView_Plex_Local(locv, viewer);CHKERRQ(ierr);
95     ierr = DMRestoreLocalVector(dm, &locv);CHKERRQ(ierr);
96   } else {
97     PetscBool isseq;
98 
99     ierr = PetscObjectTypeCompare((PetscObject) v, VECSEQ, &isseq);CHKERRQ(ierr);
100     if (isseq) {
101       ierr = VecView_Seq(v, viewer);CHKERRQ(ierr);
102     } else {
103       ierr = VecView_MPI(v, viewer);CHKERRQ(ierr);
104     }
105   }
106   PetscFunctionReturn(0);
107 }
108 
109 #undef __FUNCT__
110 #define __FUNCT__ "DMPlexView_Ascii"
111 PetscErrorCode DMPlexView_Ascii(DM dm, PetscViewer viewer)
112 {
113   DM_Plex       *mesh = (DM_Plex *) dm->data;
114   DM                cdm;
115   DMLabel           markers;
116   PetscSection      coordSection;
117   Vec               coordinates;
118   PetscViewerFormat format;
119   PetscErrorCode    ierr;
120 
121   PetscFunctionBegin;
122   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
123   ierr = DMGetDefaultSection(cdm, &coordSection);CHKERRQ(ierr);
124   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
125   ierr = PetscViewerGetFormat(viewer, &format);CHKERRQ(ierr);
126   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
127     const char *name;
128     PetscInt    maxConeSize, maxSupportSize;
129     PetscInt    pStart, pEnd, p;
130     PetscMPIInt rank, size;
131 
132     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
133     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
134     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
135     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
136     ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
137     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
138     ierr = PetscViewerASCIIPrintf(viewer, "Mesh '%s':\n", name);CHKERRQ(ierr);
139     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "Max sizes cone: %D support: %D\n", maxConeSize, maxSupportSize);CHKERRQ(ierr);
140     ierr = PetscViewerASCIIPrintf(viewer, "orientation is missing\n", name);CHKERRQ(ierr);
141     ierr = PetscViewerASCIIPrintf(viewer, "cap --> base:\n", name);CHKERRQ(ierr);
142     for (p = pStart; p < pEnd; ++p) {
143       PetscInt dof, off, s;
144 
145       ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
146       ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
147       for (s = off; s < off+dof; ++s) {
148         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D ----> %D\n", rank, p, mesh->supports[s]);CHKERRQ(ierr);
149       }
150     }
151     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
152     ierr = PetscViewerASCIIPrintf(viewer, "base <-- cap:\n", name);CHKERRQ(ierr);
153     for (p = pStart; p < pEnd; ++p) {
154       PetscInt dof, off, c;
155 
156       ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
157       ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
158       for (c = off; c < off+dof; ++c) {
159         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "[%D]: %D <---- %D (%D)\n", rank, p, mesh->cones[c], mesh->coneOrientations[c]);CHKERRQ(ierr);
160       }
161     }
162     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
163     ierr = PetscSectionGetChart(coordSection, &pStart, PETSC_NULL);CHKERRQ(ierr);
164     if (pStart >= 0) {ierr = PetscSectionVecView(coordSection, coordinates, viewer);CHKERRQ(ierr);}
165     ierr = DMPlexGetLabel(dm, "marker", &markers);CHKERRQ(ierr);
166     if (markers) {
167       ierr = DMLabelView(markers,viewer);CHKERRQ(ierr);
168     }
169     if (size > 1) {
170       PetscSF sf;
171 
172       ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
173       ierr = PetscSFView(sf, viewer);CHKERRQ(ierr);
174     }
175     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
176   } else if (format == PETSC_VIEWER_ASCII_LATEX) {
177     const char  *name;
178     const char  *colors[3] = {"red", "blue", "green"};
179     const int    numColors = 3;
180     PetscReal    scale = 2.0;
181     PetscScalar *coords;
182     PetscInt     depth, cStart, cEnd, c, vStart, vEnd, v, eStart = 0, eEnd = 0, e, p;
183     PetscMPIInt  rank, size;
184 
185     ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
186     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
187     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
188     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
189     ierr = PetscViewerASCIISynchronizedAllow(viewer, PETSC_TRUE);CHKERRQ(ierr);
190     ierr = PetscViewerASCIIPrintf(viewer, "\
191 \\documentclass[crop,multi=false]{standalone}\n\n\
192 \\usepackage{tikz}\n\
193 \\usepackage{pgflibraryshapes}\n\
194 \\usetikzlibrary{backgrounds}\n\
195 \\usetikzlibrary{arrows}\n\
196 \\begin{document}\n\
197 \\section{%s}\n\
198 \\begin{center}\n", name, 8.0/scale);CHKERRQ(ierr);
199     ierr = PetscViewerASCIIPrintf(viewer, "Mesh for process ");CHKERRQ(ierr);
200     for (p = 0; p < size; ++p) {
201       if (p > 0 && p == size-1) {
202         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
203       } else if (p > 0) {
204         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
205       }
206       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
207     }
208     ierr = PetscViewerASCIIPrintf(viewer, ".\n\n\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n");CHKERRQ(ierr);
210     /* Plot vertices */
211     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
212     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
213     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
214     for (v = vStart; v < vEnd; ++v) {
215       PetscInt off, dof, d;
216 
217       ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
218       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
219       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
220       for (d = 0; d < dof; ++d) {
221         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
222         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*PetscRealPart(coords[off+d]));CHKERRQ(ierr);
223       }
224       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", v, rank, colors[rank%numColors], v);CHKERRQ(ierr);
225     }
226     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
227     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
228     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
229     /* Plot edges */
230     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
231     ierr = PetscViewerASCIIPrintf(viewer, "\\path\n");CHKERRQ(ierr);
232     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
233     for (e = eStart; e < eEnd; ++e) {
234       const PetscInt *cone;
235       PetscInt        coneSize, offA, offB, dof, d;
236 
237       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
238       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Edge %d cone should have two vertices, not %d", e, coneSize);
239       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
240       ierr = PetscSectionGetDof(coordSection, cone[0], &dof);CHKERRQ(ierr);
241       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
242       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
243       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(");CHKERRQ(ierr);
244       for (d = 0; d < dof; ++d) {
245         if (d > 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, ",");CHKERRQ(ierr);}
246         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "%G", scale*0.5*PetscRealPart(coords[offA+d]+coords[offB+d]));CHKERRQ(ierr);
247       }
248       ierr = PetscViewerASCIISynchronizedPrintf(viewer, ") node(%D_%D) [draw,shape=circle,color=%s] {%D} --\n", e, rank, colors[rank%numColors], e);CHKERRQ(ierr);
249     }
250     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
251     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
252     ierr = PetscViewerASCIIPrintf(viewer, "(0,0);\n");CHKERRQ(ierr);
253     /* Plot cells */
254     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
255     for (c = cStart; c < cEnd; ++c) {
256       PetscInt *closure = PETSC_NULL;
257       PetscInt  closureSize, firstPoint = -1;
258 
259       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
260       ierr = PetscViewerASCIISynchronizedPrintf(viewer, "\\draw[color=%s] ", colors[rank%numColors]);CHKERRQ(ierr);
261       for (p = 0; p < closureSize*2; p += 2) {
262         const PetscInt point = closure[p];
263 
264         if ((point < vStart) || (point >= vEnd)) continue;
265         if (firstPoint >= 0) {ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- ");CHKERRQ(ierr);}
266         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "(%D_%D)", point, rank);CHKERRQ(ierr);
267         if (firstPoint < 0) firstPoint = point;
268       }
269       /* Why doesn't this work? ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- cycle;\n");CHKERRQ(ierr); */
270       ierr = PetscViewerASCIISynchronizedPrintf(viewer, " -- (%D_%D);\n", firstPoint, rank);CHKERRQ(ierr);
271       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
272     }
273     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
274     ierr = PetscViewerASCIIPrintf(viewer, "\\end{tikzpicture}\n\\end{center}\n");CHKERRQ(ierr);
275     ierr = PetscViewerASCIIPrintf(viewer, "\\end{document}\n", name);CHKERRQ(ierr);
276   } else {
277     MPI_Comm    comm = ((PetscObject) dm)->comm;
278     PetscInt   *sizes;
279     PetscInt    locDepth, depth, dim, d;
280     PetscInt    pStart, pEnd, p;
281     PetscMPIInt size;
282 
283     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
284     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
285     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
286     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
287     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
288     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
289     if (depth == 1) {
290       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
291       pEnd = pEnd - pStart;
292       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
293       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
294       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
295       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
296       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
297       pEnd = pEnd - pStart;
298       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
299       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
300       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
301       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
302     } else {
303       for (d = 0; d <= dim; d++) {
304         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
305         pEnd = pEnd - pStart;
306         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
307         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
308         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
309         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
310       }
311     }
312     ierr = PetscFree(sizes);CHKERRQ(ierr);
313   }
314   PetscFunctionReturn(0);
315 }
316 
317 #undef __FUNCT__
318 #define __FUNCT__ "DMView_Plex"
319 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
320 {
321   PetscBool      iascii, isbinary;
322   PetscErrorCode ierr;
323 
324   PetscFunctionBegin;
325   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
326   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
327   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
328   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
329   if (iascii) {
330     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
331 #if 0
332   } else if (isbinary) {
333     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
334 #endif
335   }
336   PetscFunctionReturn(0);
337 }
338 
339 #undef __FUNCT__
340 #define __FUNCT__ "DMDestroy_Plex"
341 PetscErrorCode DMDestroy_Plex(DM dm)
342 {
343   DM_Plex    *mesh = (DM_Plex *) dm->data;
344   DMLabel        next = mesh->labels;
345   PetscErrorCode ierr;
346 
347   PetscFunctionBegin;
348   if (--mesh->refct > 0) {PetscFunctionReturn(0);}
349   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
350   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
351   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
352   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
353   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
354   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
355   while (next) {
356     DMLabel tmp = next->next;
357 
358     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
359     next = tmp;
360   }
361   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
362   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
363   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
364   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
365   ierr = PetscFree(mesh);CHKERRQ(ierr);
366   PetscFunctionReturn(0);
367 }
368 
369 #undef __FUNCT__
370 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
371 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
372 {
373   const PetscInt *support = PETSC_NULL;
374   PetscInt        numAdj  = 0, maxAdjSize = *adjSize, supportSize, s;
375   PetscErrorCode  ierr;
376 
377   PetscFunctionBegin;
378   if (useClosure) {
379     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
380     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
381     for (s = 0; s < supportSize; ++s) {
382       const PetscInt *cone = PETSC_NULL;
383       PetscInt        coneSize, c, q;
384 
385       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
386       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
387       for (c = 0; c < coneSize; ++c) {
388         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
389           if (cone[c] == adj[q]) break;
390         }
391         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
392       }
393     }
394   } else {
395     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
396     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
397     for (s = 0; s < supportSize; ++s) {
398       const PetscInt *cone = PETSC_NULL;
399       PetscInt        coneSize, c, q;
400 
401       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
402       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
403       for (c = 0; c < coneSize; ++c) {
404         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
405           if (cone[c] == adj[q]) break;
406         }
407         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
408       }
409     }
410   }
411   *adjSize = numAdj;
412   PetscFunctionReturn(0);
413 }
414 
415 #undef __FUNCT__
416 #define __FUNCT__ "DMPlexGetAdjacency_Private"
417 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
418 {
419   const PetscInt *star   = tmpClosure;
420   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
421   PetscErrorCode  ierr;
422 
423   PetscFunctionBegin;
424   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt **) &star);CHKERRQ(ierr);
425   for (s = 2; s < starSize*2; s += 2) {
426     const PetscInt *closure = PETSC_NULL;
427     PetscInt        closureSize, c, q;
428 
429     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
430     for (c = 0; c < closureSize*2; c += 2) {
431       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
432         if (closure[c] == adj[q]) break;
433       }
434       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
435     }
436     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
437   }
438   *adjSize = numAdj;
439   PetscFunctionReturn(0);
440 }
441 
442 #undef __FUNCT__
443 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
444 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
445 {
446   DM_Plex *mesh = (DM_Plex *) dm->data;
447 
448   PetscFunctionBegin;
449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
450   mesh->preallocCenterDim = preallocCenterDim;
451   PetscFunctionReturn(0);
452 }
453 
454 #undef __FUNCT__
455 #define __FUNCT__ "DMPlexPreallocateOperator"
456 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
457 {
458   DM_Plex        *mesh = (DM_Plex *) dm->data;
459   MPI_Comm           comm = ((PetscObject) dm)->comm;
460   PetscSF            sf, sfDof, sfAdj;
461   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
462   PetscInt           nleaves, l, p;
463   const PetscInt    *leaves;
464   const PetscSFNode *remotes;
465   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
466   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
467   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
468   PetscLayout        rLayout;
469   PetscInt           locRows, rStart, rEnd, r;
470   PetscMPIInt        size;
471   PetscBool          useClosure, debug = PETSC_FALSE;
472   PetscErrorCode     ierr;
473 
474   PetscFunctionBegin;
475   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
476   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
477   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
478   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
479   /* Create dof SF based on point SF */
480   if (debug) {
481     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
482     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
483     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
484     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
485     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
486     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
487   }
488   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
489   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
490   if (debug) {
491     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
492     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
493   }
494   /* Create section for dof adjacency (dof ==> # adj dof) */
495   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
496   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
497   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
498   if (mesh->preallocCenterDim == dim) {
499     useClosure = PETSC_FALSE;
500   } else if (mesh->preallocCenterDim == 0) {
501     useClosure = PETSC_TRUE;
502   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
503 
504   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
505   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
506   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
507   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
508   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
509   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
510   /*   Fill in the ghost dofs on the interface */
511   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
512   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
513   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
514   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)) + 2;
515   maxAdjSize     = PetscPowInt(mesh->maxConeSize,depth) * PetscPowInt(mesh->maxSupportSize,depth) + 1;
516   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
517 
518   /*
519    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
520     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
521        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
522     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
523        Create sfAdj connecting rootSectionAdj and leafSectionAdj
524     3. Visit unowned points on interface, write adjacencies to adj
525        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
526     4. Visit owned points on interface, write adjacencies to rootAdj
527        Remove redundancy in rootAdj
528    ** The last two traversals use transitive closure
529     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
530        Allocate memory addressed by sectionAdj (cols)
531     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
532    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
533   */
534 
535   for (l = 0; l < nleaves; ++l) {
536     PetscInt dof, off, d, q;
537     PetscInt p = leaves[l], numAdj = maxAdjSize;
538 
539     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
540     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
541     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
542     for (q = 0; q < numAdj; ++q) {
543       PetscInt ndof, ncdof;
544 
545       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
546       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
547       for (d = off; d < off+dof; ++d) {
548         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
549       }
550     }
551   }
552   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
553   if (debug) {
554     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
555     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
556   }
557   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
558   if (size > 1) {
559     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
560     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
561   }
562   if (debug) {
563     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
564     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
565   }
566   /* Add in local adjacency sizes for owned dofs on interface (roots) */
567   for (p = pStart; p < pEnd; ++p) {
568     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
569 
570     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
571     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
572     if (!dof) continue;
573     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
574     if (adof <= 0) continue;
575     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
576     for (q = 0; q < numAdj; ++q) {
577       PetscInt ndof, ncdof;
578 
579       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
580       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
581       for (d = off; d < off+dof; ++d) {
582         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
583       }
584     }
585   }
586   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
587   if (debug) {
588     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
589     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
590   }
591   /* Create adj SF based on dof SF */
592   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
593   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
594   if (debug) {
595     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
596     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
597   }
598   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
599   /* Create leaf adjacency */
600   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
601   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
602   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
603   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
604   for (l = 0; l < nleaves; ++l) {
605     PetscInt dof, off, d, q;
606     PetscInt p = leaves[l], numAdj = maxAdjSize;
607 
608     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
609     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
610     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
611     for (d = off; d < off+dof; ++d) {
612       PetscInt aoff, i = 0;
613 
614       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
615       for (q = 0; q < numAdj; ++q) {
616         PetscInt  ndof, ncdof, ngoff, nd;
617 
618         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
619         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
620         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
621         for (nd = 0; nd < ndof-ncdof; ++nd) {
622           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
623           ++i;
624         }
625       }
626     }
627   }
628   /* Debugging */
629   if (debug) {
630     IS tmp;
631     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
632     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
633     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
634   }
635   /* Gather adjacenct indices to root */
636   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
637   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
638   for (r = 0; r < adjSize; ++r) {
639     rootAdj[r] = -1;
640   }
641   if (size > 1) {
642     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
643     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
644   }
645   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
646   ierr = PetscFree(adj);CHKERRQ(ierr);
647   /* Debugging */
648   if (debug) {
649     IS tmp;
650     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
651     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
652     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
653   }
654   /* Add in local adjacency indices for owned dofs on interface (roots) */
655   for (p = pStart; p < pEnd; ++p) {
656     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
657 
658     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
659     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
660     if (!dof) continue;
661     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
662     if (adof <= 0) continue;
663     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
664     for (d = off; d < off+dof; ++d) {
665       PetscInt adof, aoff, i;
666 
667       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
668       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
669       i    = adof-1;
670       for (q = 0; q < numAdj; ++q) {
671         PetscInt ndof, ncdof, ngoff, nd;
672 
673         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
674         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
675         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
676         for (nd = 0; nd < ndof-ncdof; ++nd) {
677           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
678           --i;
679         }
680       }
681     }
682   }
683   /* Debugging */
684   if (debug) {
685     IS tmp;
686     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
687     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
688     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
689   }
690   /* Compress indices */
691   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
692   for (p = pStart; p < pEnd; ++p) {
693     PetscInt dof, cdof, off, d;
694     PetscInt adof, aoff;
695 
696     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
697     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
698     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
699     if (!dof) continue;
700     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
701     if (adof <= 0) continue;
702     for (d = off; d < off+dof-cdof; ++d) {
703       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
704       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
705       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
706       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
707     }
708   }
709   /* Debugging */
710   if (debug) {
711     IS tmp;
712     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
713     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
714     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
715     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
716     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
717   }
718   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
719   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
720   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
721   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
722   for (p = pStart; p < pEnd; ++p) {
723     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
724     PetscBool found  = PETSC_TRUE;
725 
726     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
727     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
728     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
729     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
730     for (d = 0; d < dof-cdof; ++d) {
731       PetscInt ldof, rdof;
732 
733       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
734       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
735       if (ldof > 0) {
736         /* We do not own this point */
737       } else if (rdof > 0) {
738         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
739       } else {
740         found = PETSC_FALSE;
741       }
742     }
743     if (found) continue;
744     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
745     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
746     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
747     for (q = 0; q < numAdj; ++q) {
748       PetscInt ndof, ncdof, noff;
749 
750       /* Adjacent points may not be in the section chart */
751       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
752       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
753       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
754       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
755       for (d = goff; d < goff+dof-cdof; ++d) {
756         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
757       }
758     }
759   }
760   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
761   if (debug) {
762     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
763     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
764   }
765   /* Get adjacent indices */
766   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
767   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
768   for (p = pStart; p < pEnd; ++p) {
769     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
770     PetscBool found  = PETSC_TRUE;
771 
772     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
773     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
774     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
775     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
776     for (d = 0; d < dof-cdof; ++d) {
777       PetscInt ldof, rdof;
778 
779       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
780       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
781       if (ldof > 0) {
782         /* We do not own this point */
783       } else if (rdof > 0) {
784         PetscInt aoff, roff;
785 
786         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
787         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
788         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
789       } else {
790         found = PETSC_FALSE;
791       }
792     }
793     if (found) continue;
794     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
795     for (d = goff; d < goff+dof-cdof; ++d) {
796       PetscInt adof, aoff, i = 0;
797 
798       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
799       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
800       for (q = 0; q < numAdj; ++q) {
801         PetscInt        ndof, ncdof, ngoff, nd;
802         const PetscInt *ncind;
803 
804         /* Adjacent points may not be in the section chart */
805         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
806         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
807         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
808         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
809         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
810         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
811           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
812         }
813       }
814       if (i != adof) SETERRQ4(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid number of entries %D != %D for dof %D (point %D)", i, adof, d, p);
815     }
816   }
817   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
818   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
819   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
820   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
821   /* Debugging */
822   if (debug) {
823     IS tmp;
824     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
825     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
826     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
827   }
828   /* Create allocation vectors from adjacency graph */
829   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
830   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
831   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
832   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
833   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
834   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
835   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
836   /* Only loop over blocks of rows */
837   if (rStart%bs || rEnd%bs) SETERRQ3(((PetscObject) A)->comm, PETSC_ERR_ARG_WRONG, "Invalid layout [%d, %d) for matrix, must be divisible by block size %d", rStart, rEnd, bs);
838   for (r = rStart/bs; r < rEnd/bs; ++r) {
839     const PetscInt row = r*bs;
840     PetscInt numCols, cStart, c;
841 
842     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
843     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
844     for (c = cStart; c < cStart+numCols; ++c) {
845       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
846         ++dnz[r-rStart];
847         if (cols[c] >= row) {++dnzu[r-rStart];}
848       } else {
849         ++onz[r-rStart];
850         if (cols[c] >= row) {++onzu[r-rStart];}
851       }
852     }
853   }
854   if (bs > 1) {
855     for (r = 0; r < locRows/bs; ++r) {
856       dnz[r]  /= bs;
857       onz[r]  /= bs;
858       dnzu[r] /= bs;
859       onzu[r] /= bs;
860     }
861   }
862   /* Set matrix pattern */
863   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
864   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
865   /* Fill matrix with zeros */
866   if (fillMatrix) {
867     PetscScalar *values;
868     PetscInt     maxRowLen = 0;
869 
870     for (r = rStart; r < rEnd; ++r) {
871       PetscInt len;
872 
873       ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
874       maxRowLen = PetscMax(maxRowLen, len);
875     }
876     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
877     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
878     for (r = rStart; r < rEnd; ++r) {
879       PetscInt numCols, cStart;
880 
881       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
882       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
883       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
884     }
885     ierr = PetscFree(values);CHKERRQ(ierr);
886     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
887     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
888   }
889   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
890   ierr = PetscFree(cols);CHKERRQ(ierr);
891   PetscFunctionReturn(0);
892 }
893 
894 #if 0
895 #undef __FUNCT__
896 #define __FUNCT__ "DMPlexPreallocateOperator_2"
897 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
898 {
899   PetscErrorCode ierr;
900   PetscInt c,cStart,cEnd,pStart,pEnd;
901   PetscInt *tmpClosure,*tmpAdj,*visits;
902 
903   PetscFunctionBegin;
904   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
905   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
906   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
907   maxClosureSize = 2*PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth));
908   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
909   npoints = pEnd - pStart;
910   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
911   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
912   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
913   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
914   for (c=cStart; c<cEnd; c++) {
915     PetscInt *support = tmpClosure;
916     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
917     for (p=0; p<supportSize; p++) {
918       lvisits[support[p]]++;
919     }
920   }
921   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
922   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
923   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
924   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
925 
926   ierr = PetscSFGetRanks();CHKERRQ(ierr);
927 
928 
929   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
930   for (c=cStart; c<cEnd; c++) {
931     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
932     /*
933      Depth-first walk of transitive closure.
934      At each leaf frame f of transitive closure that we see, add 1/visits[f] to each pair (p,q) not marked as done in cellmat.
935      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
936      */
937   }
938 
939   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
940   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
941   PetscFunctionReturn(0);
942 }
943 #endif
944 
945 #undef __FUNCT__
946 #define __FUNCT__ "DMCreateMatrix_Plex"
947 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
948 {
949   PetscSection   section, sectionGlobal;
950   PetscInt       bs = -1;
951   PetscInt       localSize;
952   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
953   PetscErrorCode ierr;
954 
955   PetscFunctionBegin;
956 #if !defined(PETSC_USE_DYNAMIC_LIBRARIES)
957   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
958 #endif
959   if (!mtype) mtype = MATAIJ;
960   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
961   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
962   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
963   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
964   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
965   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
966   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
967   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
968   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
969   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
970   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
971   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
972   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
973   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
974   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
975   /* Check for symmetric storage */
976   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
977   if (isSymmetric) {
978     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
979   }
980   if (!isShell) {
981     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
982     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal;
983 
984     if (bs < 0) {
985       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
986         PetscInt pStart, pEnd, p, dof;
987 
988         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
989         for (p = pStart; p < pEnd; ++p) {
990           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
991           if (dof) {
992             bs = dof;
993             break;
994           }
995         }
996       } else {
997         bs = 1;
998       }
999       /* Must have same blocksize on all procs (some might have no points) */
1000       bsLocal = bs;
1001       ierr = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1002     }
1003     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1004     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1005     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1006     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1007     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1008     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1009     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1010   }
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 #undef __FUNCT__
1015 #define __FUNCT__ "DMPlexGetDimension"
1016 /*@
1017   DMPlexGetDimension - Return the topological mesh dimension
1018 
1019   Not collective
1020 
1021   Input Parameter:
1022 . mesh - The DMPlex
1023 
1024   Output Parameter:
1025 . dim - The topological mesh dimension
1026 
1027   Level: beginner
1028 
1029 .seealso: DMPlexCreate()
1030 @*/
1031 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1032 {
1033   DM_Plex *mesh = (DM_Plex *) dm->data;
1034 
1035   PetscFunctionBegin;
1036   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1037   PetscValidPointer(dim, 2);
1038   *dim = mesh->dim;
1039   PetscFunctionReturn(0);
1040 }
1041 
1042 #undef __FUNCT__
1043 #define __FUNCT__ "DMPlexSetDimension"
1044 /*@
1045   DMPlexSetDimension - Set the topological mesh dimension
1046 
1047   Collective on mesh
1048 
1049   Input Parameters:
1050 + mesh - The DMPlex
1051 - dim - The topological mesh dimension
1052 
1053   Level: beginner
1054 
1055 .seealso: DMPlexCreate()
1056 @*/
1057 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1058 {
1059   DM_Plex *mesh = (DM_Plex *) dm->data;
1060 
1061   PetscFunctionBegin;
1062   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1063   PetscValidLogicalCollectiveInt(dm, dim, 2);
1064   mesh->dim = dim;
1065   mesh->preallocCenterDim = dim;
1066   PetscFunctionReturn(0);
1067 }
1068 
1069 #undef __FUNCT__
1070 #define __FUNCT__ "DMPlexGetChart"
1071 /*@
1072   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1073 
1074   Not collective
1075 
1076   Input Parameter:
1077 . mesh - The DMPlex
1078 
1079   Output Parameters:
1080 + pStart - The first mesh point
1081 - pEnd   - The upper bound for mesh points
1082 
1083   Level: beginner
1084 
1085 .seealso: DMPlexCreate(), DMPlexSetChart()
1086 @*/
1087 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1088 {
1089   DM_Plex    *mesh = (DM_Plex *) dm->data;
1090   PetscErrorCode ierr;
1091 
1092   PetscFunctionBegin;
1093   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1094   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1095   PetscFunctionReturn(0);
1096 }
1097 
1098 #undef __FUNCT__
1099 #define __FUNCT__ "DMPlexSetChart"
1100 /*@
1101   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1102 
1103   Not collective
1104 
1105   Input Parameters:
1106 + mesh - The DMPlex
1107 . pStart - The first mesh point
1108 - pEnd   - The upper bound for mesh points
1109 
1110   Output Parameters:
1111 
1112   Level: beginner
1113 
1114 .seealso: DMPlexCreate(), DMPlexGetChart()
1115 @*/
1116 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1117 {
1118   DM_Plex    *mesh = (DM_Plex *) dm->data;
1119   PetscErrorCode ierr;
1120 
1121   PetscFunctionBegin;
1122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1123   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1124   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 #undef __FUNCT__
1129 #define __FUNCT__ "DMPlexGetConeSize"
1130 /*@
1131   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1132 
1133   Not collective
1134 
1135   Input Parameters:
1136 + mesh - The DMPlex
1137 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1138 
1139   Output Parameter:
1140 . size - The cone size for point p
1141 
1142   Level: beginner
1143 
1144 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1145 @*/
1146 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1147 {
1148   DM_Plex    *mesh = (DM_Plex *) dm->data;
1149   PetscErrorCode ierr;
1150 
1151   PetscFunctionBegin;
1152   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1153   PetscValidPointer(size, 3);
1154   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1155   PetscFunctionReturn(0);
1156 }
1157 
1158 #undef __FUNCT__
1159 #define __FUNCT__ "DMPlexSetConeSize"
1160 /*@
1161   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1162 
1163   Not collective
1164 
1165   Input Parameters:
1166 + mesh - The DMPlex
1167 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1168 - size - The cone size for point p
1169 
1170   Output Parameter:
1171 
1172   Note:
1173   This should be called after DMPlexSetChart().
1174 
1175   Level: beginner
1176 
1177 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1178 @*/
1179 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1180 {
1181   DM_Plex    *mesh = (DM_Plex *) dm->data;
1182   PetscErrorCode ierr;
1183 
1184   PetscFunctionBegin;
1185   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1186   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1187   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1188   PetscFunctionReturn(0);
1189 }
1190 
1191 #undef __FUNCT__
1192 #define __FUNCT__ "DMPlexGetCone"
1193 /*@C
1194   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1195 
1196   Not collective
1197 
1198   Input Parameters:
1199 + mesh - The DMPlex
1200 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1201 
1202   Output Parameter:
1203 . cone - An array of points which are on the in-edges for point p
1204 
1205   Level: beginner
1206 
1207   Note:
1208   This routine is not available in Fortran.
1209 
1210 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1211 @*/
1212 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1213 {
1214   DM_Plex    *mesh = (DM_Plex *) dm->data;
1215   PetscInt       off;
1216   PetscErrorCode ierr;
1217 
1218   PetscFunctionBegin;
1219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1220   PetscValidPointer(cone, 3);
1221   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1222   *cone = &mesh->cones[off];
1223   PetscFunctionReturn(0);
1224 }
1225 
1226 #undef __FUNCT__
1227 #define __FUNCT__ "DMPlexSetCone"
1228 /*@
1229   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1230 
1231   Not collective
1232 
1233   Input Parameters:
1234 + mesh - The DMPlex
1235 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1236 - cone - An array of points which are on the in-edges for point p
1237 
1238   Output Parameter:
1239 
1240   Note:
1241   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1242 
1243   Level: beginner
1244 
1245 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1246 @*/
1247 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1248 {
1249   DM_Plex    *mesh = (DM_Plex *) dm->data;
1250   PetscInt       pStart, pEnd;
1251   PetscInt       dof, off, c;
1252   PetscErrorCode ierr;
1253 
1254   PetscFunctionBegin;
1255   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1256   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1257   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1258   if (dof) PetscValidPointer(cone, 3);
1259   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1260   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1261   for (c = 0; c < dof; ++c) {
1262     if ((cone[c] < pStart) || (cone[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", cone[c], pStart, pEnd);
1263     mesh->cones[off+c] = cone[c];
1264   }
1265   PetscFunctionReturn(0);
1266 }
1267 
1268 #undef __FUNCT__
1269 #define __FUNCT__ "DMPlexGetConeOrientation"
1270 /*@C
1271   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1272 
1273   Not collective
1274 
1275   Input Parameters:
1276 + mesh - The DMPlex
1277 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1278 
1279   Output Parameter:
1280 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1281                     integer giving the prescription for cone traversal. If it is negative, the cone is
1282                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1283                     the index of the cone point on which to start.
1284 
1285   Level: beginner
1286 
1287   Note:
1288   This routine is not available in Fortran.
1289 
1290 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1291 @*/
1292 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1293 {
1294   DM_Plex    *mesh = (DM_Plex *) dm->data;
1295   PetscInt       off;
1296   PetscErrorCode ierr;
1297 
1298   PetscFunctionBegin;
1299   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1300 #if defined(PETSC_USE_DEBUG)
1301   {
1302     PetscInt dof;
1303     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1304     if (dof) PetscValidPointer(coneOrientation, 3);
1305   }
1306 #endif
1307   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1308   *coneOrientation = &mesh->coneOrientations[off];
1309   PetscFunctionReturn(0);
1310 }
1311 
1312 #undef __FUNCT__
1313 #define __FUNCT__ "DMPlexSetConeOrientation"
1314 /*@
1315   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1316 
1317   Not collective
1318 
1319   Input Parameters:
1320 + mesh - The DMPlex
1321 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1322 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1323                     integer giving the prescription for cone traversal. If it is negative, the cone is
1324                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1325                     the index of the cone point on which to start.
1326 
1327   Output Parameter:
1328 
1329   Note:
1330   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1331 
1332   Level: beginner
1333 
1334 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1335 @*/
1336 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1337 {
1338   DM_Plex    *mesh = (DM_Plex *) dm->data;
1339   PetscInt       pStart, pEnd;
1340   PetscInt       dof, off, c;
1341   PetscErrorCode ierr;
1342 
1343   PetscFunctionBegin;
1344   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1345   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1346   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1347   if (dof) PetscValidPointer(coneOrientation, 3);
1348   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1349   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1350   for (c = 0; c < dof; ++c) {
1351     PetscInt cdof, o = coneOrientation[c];
1352 
1353     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1354     if (o && ((o < -(cdof+1)) || (o >= cdof))) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone orientation %D is not in the valid range [%D. %D)", o, -(cdof+1), cdof);
1355     mesh->coneOrientations[off+c] = o;
1356   }
1357   PetscFunctionReturn(0);
1358 }
1359 
1360 #undef __FUNCT__
1361 #define __FUNCT__ "DMPlexInsertCone"
1362 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1363 {
1364   DM_Plex    *mesh = (DM_Plex *) dm->data;
1365   PetscInt       pStart, pEnd;
1366   PetscInt       dof, off;
1367   PetscErrorCode ierr;
1368 
1369   PetscFunctionBegin;
1370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1371   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1372   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1373   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1374   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1375   if ((conePoint < pStart) || (conePoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone point %D is not in the valid range [%D, %D)", conePoint, pStart, pEnd);
1376   if (conePos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone position %D of point %D is not in the valid range [0, %D)", conePos, p, dof);
1377   mesh->cones[off+conePos] = conePoint;
1378   PetscFunctionReturn(0);
1379 }
1380 
1381 #undef __FUNCT__
1382 #define __FUNCT__ "DMPlexGetSupportSize"
1383 /*@
1384   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1385 
1386   Not collective
1387 
1388   Input Parameters:
1389 + mesh - The DMPlex
1390 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1391 
1392   Output Parameter:
1393 . size - The support size for point p
1394 
1395   Level: beginner
1396 
1397 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1398 @*/
1399 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1400 {
1401   DM_Plex    *mesh = (DM_Plex *) dm->data;
1402   PetscErrorCode ierr;
1403 
1404   PetscFunctionBegin;
1405   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1406   PetscValidPointer(size, 3);
1407   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1408   PetscFunctionReturn(0);
1409 }
1410 
1411 #undef __FUNCT__
1412 #define __FUNCT__ "DMPlexSetSupportSize"
1413 /*@
1414   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1415 
1416   Not collective
1417 
1418   Input Parameters:
1419 + mesh - The DMPlex
1420 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1421 - size - The support size for point p
1422 
1423   Output Parameter:
1424 
1425   Note:
1426   This should be called after DMPlexSetChart().
1427 
1428   Level: beginner
1429 
1430 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1431 @*/
1432 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1433 {
1434   DM_Plex    *mesh = (DM_Plex *) dm->data;
1435   PetscErrorCode ierr;
1436 
1437   PetscFunctionBegin;
1438   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1439   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1440   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1441   PetscFunctionReturn(0);
1442 }
1443 
1444 #undef __FUNCT__
1445 #define __FUNCT__ "DMPlexGetSupport"
1446 /*@C
1447   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1448 
1449   Not collective
1450 
1451   Input Parameters:
1452 + mesh - The DMPlex
1453 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1454 
1455   Output Parameter:
1456 . support - An array of points which are on the out-edges for point p
1457 
1458   Level: beginner
1459 
1460 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1461 @*/
1462 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1463 {
1464   DM_Plex    *mesh = (DM_Plex *) dm->data;
1465   PetscInt       off;
1466   PetscErrorCode ierr;
1467 
1468   PetscFunctionBegin;
1469   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1470   PetscValidPointer(support, 3);
1471   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1472   *support = &mesh->supports[off];
1473   PetscFunctionReturn(0);
1474 }
1475 
1476 #undef __FUNCT__
1477 #define __FUNCT__ "DMPlexSetSupport"
1478 /*@
1479   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1480 
1481   Not collective
1482 
1483   Input Parameters:
1484 + mesh - The DMPlex
1485 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1486 - support - An array of points which are on the in-edges for point p
1487 
1488   Output Parameter:
1489 
1490   Note:
1491   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1492 
1493   Level: beginner
1494 
1495 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1496 @*/
1497 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1498 {
1499   DM_Plex    *mesh = (DM_Plex *) dm->data;
1500   PetscInt       pStart, pEnd;
1501   PetscInt       dof, off, c;
1502   PetscErrorCode ierr;
1503 
1504   PetscFunctionBegin;
1505   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1506   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1507   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1508   if (dof) PetscValidPointer(support, 3);
1509   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1510   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1511   for (c = 0; c < dof; ++c) {
1512     if ((support[c] < pStart) || (support[c] >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", support[c], pStart, pEnd);
1513     mesh->supports[off+c] = support[c];
1514   }
1515   PetscFunctionReturn(0);
1516 }
1517 
1518 #undef __FUNCT__
1519 #define __FUNCT__ "DMPlexInsertSupport"
1520 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1521 {
1522   DM_Plex    *mesh = (DM_Plex *) dm->data;
1523   PetscInt       pStart, pEnd;
1524   PetscInt       dof, off;
1525   PetscErrorCode ierr;
1526 
1527   PetscFunctionBegin;
1528   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1529   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1530   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1531   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1532   if ((p < pStart) || (p >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Mesh point %D is not in the valid range [%D, %D)", p, pStart, pEnd);
1533   if ((supportPoint < pStart) || (supportPoint >= pEnd)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support point %D is not in the valid range [%D, %D)", supportPoint, pStart, pEnd);
1534   if (supportPos >= dof) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Support position %D of point %D is not in the valid range [0, %D)", supportPos, p, dof);
1535   mesh->supports[off+supportPos] = supportPoint;
1536   PetscFunctionReturn(0);
1537 }
1538 
1539 #undef __FUNCT__
1540 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1541 /*@C
1542   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1543 
1544   Not collective
1545 
1546   Input Parameters:
1547 + mesh - The DMPlex
1548 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1549 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1550 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1551 
1552   Output Parameters:
1553 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1554 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1555 
1556   Note:
1557   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1558 
1559   Level: beginner
1560 
1561 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1562 @*/
1563 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1564 {
1565   DM_Plex     *mesh = (DM_Plex *) dm->data;
1566   PetscInt       *closure, *fifo;
1567   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1568   PetscInt        tmpSize, t;
1569   PetscInt        depth = 0, maxSize;
1570   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1571   PetscErrorCode  ierr;
1572 
1573   PetscFunctionBegin;
1574   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1575   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1576   maxSize = 2*PetscMax(PetscMax(PetscPowInt(mesh->maxConeSize,depth),PetscPowInt(mesh->maxSupportSize,depth)),depth) + 2;
1577   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1578   if (*points) {
1579     closure = *points;
1580   } else {
1581     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1582   }
1583   closure[0] = p; closure[1] = 0;
1584   /* This is only 1-level */
1585   if (useCone) {
1586     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1587     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1588     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1589   } else {
1590     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1591     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1592   }
1593   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1594     const PetscInt cp = tmp[t];
1595     const PetscInt co = tmpO ? tmpO[t] : 0;
1596 
1597     closure[closureSize]   = cp;
1598     closure[closureSize+1] = co;
1599     fifo[fifoSize]         = cp;
1600     fifo[fifoSize+1]       = co;
1601   }
1602   while (fifoSize - fifoStart) {
1603     const PetscInt q   = fifo[fifoStart];
1604     const PetscInt o   = fifo[fifoStart+1];
1605     const PetscInt rev = o >= 0 ? 0 : 1;
1606     const PetscInt off = rev ? -(o+1) : o;
1607 
1608     if (useCone) {
1609       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1610       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1611       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1612     } else {
1613       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1614       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1615       tmpO = PETSC_NULL;
1616     }
1617     for (t = 0; t < tmpSize; ++t) {
1618       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1619       const PetscInt cp = tmp[i];
1620       /* Must propogate orientation */
1621       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1622       PetscInt       c;
1623 
1624       /* Check for duplicate */
1625       for (c = 0; c < closureSize; c += 2) {
1626         if (closure[c] == cp) break;
1627       }
1628       if (c == closureSize) {
1629         closure[closureSize]   = cp;
1630         closure[closureSize+1] = co;
1631         fifo[fifoSize]         = cp;
1632         fifo[fifoSize+1]       = co;
1633         closureSize += 2;
1634         fifoSize    += 2;
1635       }
1636     }
1637     fifoStart += 2;
1638   }
1639   if (numPoints) *numPoints = closureSize/2;
1640   if (points)    *points    = closure;
1641   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1642   PetscFunctionReturn(0);
1643 }
1644 
1645 #undef __FUNCT__
1646 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1647 /*@C
1648   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1649 
1650   Not collective
1651 
1652   Input Parameters:
1653 + mesh - The DMPlex
1654 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1655 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1656 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1657 
1658   Output Parameters:
1659 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1660 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1661 
1662   Note:
1663   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1664 
1665   Level: beginner
1666 
1667 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1668 @*/
1669 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1670 {
1671   PetscErrorCode  ierr;
1672 
1673   PetscFunctionBegin;
1674   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1675   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1676   PetscFunctionReturn(0);
1677 }
1678 
1679 #undef __FUNCT__
1680 #define __FUNCT__ "DMPlexGetFaces"
1681 /*
1682   DMPlexGetFaces -
1683 
1684   Note: This will only work for cell-vertex meshes.
1685 */
1686 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1687 {
1688   DM_Plex     *mesh  = (DM_Plex *) dm->data;
1689   const PetscInt *cone  = PETSC_NULL;
1690   PetscInt        depth = 0, dim, coneSize;
1691   PetscErrorCode  ierr;
1692 
1693   PetscFunctionBegin;
1694   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1695   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1696   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1697   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1698   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1699   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1700   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1701   switch (dim) {
1702   case 2:
1703     switch (coneSize) {
1704     case 3:
1705       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1706       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1707       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1708       *numFaces = 3;
1709       *faceSize = 2;
1710       *faces    = mesh->facesTmp;
1711       break;
1712     case 4:
1713       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1714       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1715       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1716       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1717       *numFaces = 4;
1718       *faceSize = 2;
1719       *faces    = mesh->facesTmp;
1720       break;
1721     default:
1722       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1723     }
1724     break;
1725   case 3:
1726     switch (coneSize) {
1727     case 3:
1728       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1729       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1730       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1731       *numFaces = 3;
1732       *faceSize = 2;
1733       *faces    = mesh->facesTmp;
1734       break;
1735     case 4:
1736       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1737       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1738       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1739       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1740       *numFaces = 4;
1741       *faceSize = 3;
1742       *faces    = mesh->facesTmp;
1743       break;
1744     default:
1745       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1746     }
1747     break;
1748   default:
1749     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1750   }
1751   PetscFunctionReturn(0);
1752 }
1753 
1754 #undef __FUNCT__
1755 #define __FUNCT__ "DMPlexGetMaxSizes"
1756 /*@
1757   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1758 
1759   Not collective
1760 
1761   Input Parameter:
1762 . mesh - The DMPlex
1763 
1764   Output Parameters:
1765 + maxConeSize - The maximum number of in-edges
1766 - maxSupportSize - The maximum number of out-edges
1767 
1768   Level: beginner
1769 
1770 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1771 @*/
1772 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1773 {
1774   DM_Plex *mesh = (DM_Plex *) dm->data;
1775 
1776   PetscFunctionBegin;
1777   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1778   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1779   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1780   PetscFunctionReturn(0);
1781 }
1782 
1783 #undef __FUNCT__
1784 #define __FUNCT__ "DMSetUp_Plex"
1785 PetscErrorCode DMSetUp_Plex(DM dm)
1786 {
1787   DM_Plex    *mesh = (DM_Plex *) dm->data;
1788   PetscInt       size;
1789   PetscErrorCode ierr;
1790 
1791   PetscFunctionBegin;
1792   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1793   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1794   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1795   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1796   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1797   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1798   if (mesh->maxSupportSize) {
1799     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1800     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1801     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1802   }
1803   PetscFunctionReturn(0);
1804 }
1805 
1806 #undef __FUNCT__
1807 #define __FUNCT__ "DMCreateSubDM_Plex"
1808 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1809 {
1810   PetscSection   section, sectionGlobal;
1811   PetscInt      *subIndices;
1812   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1813   PetscErrorCode ierr;
1814 
1815   PetscFunctionBegin;
1816   if (!numFields) PetscFunctionReturn(0);
1817   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1818   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1819   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1820   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1821   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1822   if (numFields > nF) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Number of requested fields %d greater than number of DM fields %d", numFields, nF);
1823   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1824   for (p = pStart; p < pEnd; ++p) {
1825     PetscInt gdof;
1826 
1827     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1828     if (gdof > 0) {
1829       for (f = 0; f < numFields; ++f) {
1830         PetscInt fdof, fcdof;
1831 
1832         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1833         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1834         subSize += fdof-fcdof;
1835       }
1836     }
1837   }
1838   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1839   for (p = pStart; p < pEnd; ++p) {
1840     PetscInt gdof, goff;
1841 
1842     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1843     if (gdof > 0) {
1844       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1845       for (f = 0; f < numFields; ++f) {
1846         PetscInt fdof, fcdof, fc, f2, poff = 0;
1847 
1848         /* Can get rid of this loop by storing field information in the global section */
1849         for (f2 = 0; f2 < fields[f]; ++f2) {
1850           ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1851           ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1852           poff += fdof-fcdof;
1853         }
1854         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1855         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1856         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1857           subIndices[subOff] = goff+poff+fc;
1858         }
1859       }
1860     }
1861   }
1862   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1863   if (subdm) {
1864     PetscSection subsection;
1865     PetscBool    haveNull = PETSC_FALSE;
1866     PetscInt     f, nf = 0;
1867 
1868     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1869     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1870     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1871     for (f = 0; f < numFields; ++f) {
1872       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1873       if ((*subdm)->nullspaceConstructors[f]) {
1874         haveNull = PETSC_TRUE;
1875         nf       = f;
1876       }
1877     }
1878     if (haveNull) {
1879       MatNullSpace nullSpace;
1880 
1881       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1882       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1883       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1884     }
1885     if (dm->fields) {
1886       if (nF != dm->numFields) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "The number of DM fields %d does not match the number of Section fields %d", dm->numFields, nF);
1887       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1888       for (f = 0; f < numFields; ++f) {
1889         ierr = PetscObjectListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1890       }
1891       if (numFields == 1) {
1892         MatNullSpace space;
1893         Mat          pmat;
1894 
1895         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject *) &space);CHKERRQ(ierr);
1896         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1897         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject *) &space);CHKERRQ(ierr);
1898         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1899         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject *) &pmat);CHKERRQ(ierr);
1900         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1901       }
1902     }
1903   }
1904   PetscFunctionReturn(0);
1905 }
1906 
1907 #undef __FUNCT__
1908 #define __FUNCT__ "DMPlexSymmetrize"
1909 /*@
1910   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1911 
1912   Not collective
1913 
1914   Input Parameter:
1915 . mesh - The DMPlex
1916 
1917   Output Parameter:
1918 
1919   Note:
1920   This should be called after all calls to DMPlexSetCone()
1921 
1922   Level: beginner
1923 
1924 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1925 @*/
1926 PetscErrorCode DMPlexSymmetrize(DM dm)
1927 {
1928   DM_Plex    *mesh = (DM_Plex *) dm->data;
1929   PetscInt      *offsets;
1930   PetscInt       supportSize;
1931   PetscInt       pStart, pEnd, p;
1932   PetscErrorCode ierr;
1933 
1934   PetscFunctionBegin;
1935   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1936   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1937   /* Calculate support sizes */
1938   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1939   for (p = pStart; p < pEnd; ++p) {
1940     PetscInt dof, off, c;
1941 
1942     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1943     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1944     for (c = off; c < off+dof; ++c) {
1945       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1946     }
1947   }
1948   for (p = pStart; p < pEnd; ++p) {
1949     PetscInt dof;
1950 
1951     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1952     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1953   }
1954   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1955   /* Calculate supports */
1956   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1957   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1958   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1959   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1960   for (p = pStart; p < pEnd; ++p) {
1961     PetscInt dof, off, c;
1962 
1963     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1964     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1965     for (c = off; c < off+dof; ++c) {
1966       const PetscInt q = mesh->cones[c];
1967       PetscInt       offS;
1968 
1969       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1970       mesh->supports[offS+offsets[q]] = p;
1971       ++offsets[q];
1972     }
1973   }
1974   ierr = PetscFree(offsets);CHKERRQ(ierr);
1975   PetscFunctionReturn(0);
1976 }
1977 
1978 #undef __FUNCT__
1979 #define __FUNCT__ "DMPlexSetDepth_Private"
1980 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1981 {
1982   PetscInt       d;
1983   PetscErrorCode ierr;
1984 
1985   PetscFunctionBegin;
1986   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1987   if (d < 0) {
1988     /* We are guaranteed that the point has a cone since the depth was not yet set */
1989     const PetscInt *cone = PETSC_NULL;
1990     PetscInt        dCone;
1991 
1992     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1993     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
1994     d    = dCone+1;
1995     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
1996   }
1997   *depth = d;
1998   PetscFunctionReturn(0);
1999 }
2000 
2001 #undef __FUNCT__
2002 #define __FUNCT__ "DMPlexStratify"
2003 /*@
2004   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2005   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2006   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2007   the DAG.
2008 
2009   Not collective
2010 
2011   Input Parameter:
2012 . mesh - The DMPlex
2013 
2014   Output Parameter:
2015 
2016   Notes:
2017   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2018   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2019 
2020   This should be called after all calls to DMPlexSymmetrize()
2021 
2022   Level: beginner
2023 
2024 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2025 @*/
2026 PetscErrorCode DMPlexStratify(DM dm)
2027 {
2028   DM_Plex    *mesh = (DM_Plex *) dm->data;
2029   PetscInt       pStart, pEnd, p;
2030   PetscInt       numRoots = 0, numLeaves = 0;
2031   PetscErrorCode ierr;
2032 
2033   PetscFunctionBegin;
2034   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2035   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2036   /* Calculate depth */
2037   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2038   /* Initialize roots and count leaves */
2039   for (p = pStart; p < pEnd; ++p) {
2040     PetscInt coneSize, supportSize;
2041 
2042     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2043     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2044     if (!coneSize && supportSize) {
2045       ++numRoots;
2046       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2047     } else if (!supportSize && coneSize) {
2048       ++numLeaves;
2049     } else if (!supportSize && !coneSize) {
2050       /* Isolated points */
2051       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2052     }
2053   }
2054   if (numRoots + numLeaves == (pEnd - pStart)) {
2055     for (p = pStart; p < pEnd; ++p) {
2056       PetscInt coneSize, supportSize;
2057 
2058       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2059       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2060       if (!supportSize && coneSize) {
2061         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2062       }
2063     }
2064   } else {
2065     /* This might be slow since lookup is not fast */
2066     for (p = pStart; p < pEnd; ++p) {
2067       PetscInt depth;
2068 
2069       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2070     }
2071   }
2072   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2073   PetscFunctionReturn(0);
2074 }
2075 
2076 #undef __FUNCT__
2077 #define __FUNCT__ "DMPlexGetJoin"
2078 /*@C
2079   DMPlexGetJoin - Get an array for the join of the set of points
2080 
2081   Not Collective
2082 
2083   Input Parameters:
2084 + dm - The DMPlex object
2085 . numPoints - The number of input points for the join
2086 - points - The input points
2087 
2088   Output Parameters:
2089 + numCoveredPoints - The number of points in the join
2090 - coveredPoints - The points in the join
2091 
2092   Level: intermediate
2093 
2094   Note: Currently, this is restricted to a single level join
2095 
2096 .keywords: mesh
2097 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2098 @*/
2099 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2100 {
2101   DM_Plex    *mesh = (DM_Plex *) dm->data;
2102   PetscInt      *join[2];
2103   PetscInt       joinSize, i = 0;
2104   PetscInt       dof, off, p, c, m;
2105   PetscErrorCode ierr;
2106 
2107   PetscFunctionBegin;
2108   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2109   PetscValidPointer(points, 2);
2110   PetscValidPointer(numCoveredPoints, 3);
2111   PetscValidPointer(coveredPoints, 4);
2112   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2113   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2114   /* Copy in support of first point */
2115   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2116   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2117   for (joinSize = 0; joinSize < dof; ++joinSize) {
2118     join[i][joinSize] = mesh->supports[off+joinSize];
2119   }
2120   /* Check each successive support */
2121   for (p = 1; p < numPoints; ++p) {
2122     PetscInt newJoinSize = 0;
2123 
2124     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2125     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2126     for (c = 0; c < dof; ++c) {
2127       const PetscInt point = mesh->supports[off+c];
2128 
2129       for (m = 0; m < joinSize; ++m) {
2130         if (point == join[i][m]) {
2131           join[1-i][newJoinSize++] = point;
2132           break;
2133         }
2134       }
2135     }
2136     joinSize = newJoinSize;
2137     i = 1-i;
2138   }
2139   *numCoveredPoints = joinSize;
2140   *coveredPoints    = join[i];
2141   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2142   PetscFunctionReturn(0);
2143 }
2144 
2145 #undef __FUNCT__
2146 #define __FUNCT__ "DMPlexRestoreJoin"
2147 /*@C
2148   DMPlexRestoreJoin - Restore an array for the join of the set of points
2149 
2150   Not Collective
2151 
2152   Input Parameters:
2153 + dm - The DMPlex object
2154 . numPoints - The number of input points for the join
2155 - points - The input points
2156 
2157   Output Parameters:
2158 + numCoveredPoints - The number of points in the join
2159 - coveredPoints - The points in the join
2160 
2161   Level: intermediate
2162 
2163 .keywords: mesh
2164 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2165 @*/
2166 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2167 {
2168   PetscErrorCode ierr;
2169 
2170   PetscFunctionBegin;
2171   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2172   PetscValidPointer(coveredPoints, 4);
2173   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2174   PetscFunctionReturn(0);
2175 }
2176 
2177 #undef __FUNCT__
2178 #define __FUNCT__ "DMPlexGetFullJoin"
2179 /*@C
2180   DMPlexGetFullJoin - Get an array for the join of the set of points
2181 
2182   Not Collective
2183 
2184   Input Parameters:
2185 + dm - The DMPlex object
2186 . numPoints - The number of input points for the join
2187 - points - The input points
2188 
2189   Output Parameters:
2190 + numCoveredPoints - The number of points in the join
2191 - coveredPoints - The points in the join
2192 
2193   Level: intermediate
2194 
2195 .keywords: mesh
2196 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2197 @*/
2198 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2199 {
2200   DM_Plex    *mesh = (DM_Plex *) dm->data;
2201   PetscInt      *offsets, **closures;
2202   PetscInt      *join[2];
2203   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2204   PetscInt       p, d, c, m;
2205   PetscErrorCode ierr;
2206 
2207   PetscFunctionBegin;
2208   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2209   PetscValidPointer(points, 2);
2210   PetscValidPointer(numCoveredPoints, 3);
2211   PetscValidPointer(coveredPoints, 4);
2212 
2213   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2214   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2215   ierr = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2216   ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2217   maxSize = PetscPowInt(mesh->maxSupportSize,depth);
2218   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2219   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2220 
2221   for (p = 0; p < numPoints; ++p) {
2222     PetscInt closureSize;
2223 
2224     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2225     offsets[p*(depth+2)+0] = 0;
2226     for (d = 0; d < depth+1; ++d) {
2227       PetscInt pStart, pEnd, i;
2228 
2229       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2230       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2231         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2232           offsets[p*(depth+2)+d+1] = i;
2233           break;
2234         }
2235       }
2236       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2237     }
2238     if (offsets[p*(depth+2)+depth+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(depth+2)+depth+1], closureSize);
2239   }
2240   for (d = 0; d < depth+1; ++d) {
2241     PetscInt dof;
2242 
2243     /* Copy in support of first point */
2244     dof = offsets[d+1] - offsets[d];
2245     for (joinSize = 0; joinSize < dof; ++joinSize) {
2246       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2247     }
2248     /* Check each successive cone */
2249     for (p = 1; p < numPoints && joinSize; ++p) {
2250       PetscInt newJoinSize = 0;
2251 
2252       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2253       for (c = 0; c < dof; ++c) {
2254         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2255 
2256         for (m = 0; m < joinSize; ++m) {
2257           if (point == join[i][m]) {
2258             join[1-i][newJoinSize++] = point;
2259             break;
2260           }
2261         }
2262       }
2263       joinSize = newJoinSize;
2264       i = 1-i;
2265     }
2266     if (joinSize) break;
2267   }
2268   *numCoveredPoints = joinSize;
2269   *coveredPoints    = join[i];
2270   for (p = 0; p < numPoints; ++p) {
2271     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2272   }
2273   ierr = PetscFree(closures);CHKERRQ(ierr);
2274   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2275   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2276   PetscFunctionReturn(0);
2277 }
2278 
2279 #undef __FUNCT__
2280 #define __FUNCT__ "DMPlexGetMeet"
2281 /*@C
2282   DMPlexGetMeet - Get an array for the meet of the set of points
2283 
2284   Not Collective
2285 
2286   Input Parameters:
2287 + dm - The DMPlex object
2288 . numPoints - The number of input points for the meet
2289 - points - The input points
2290 
2291   Output Parameters:
2292 + numCoveredPoints - The number of points in the meet
2293 - coveredPoints - The points in the meet
2294 
2295   Level: intermediate
2296 
2297   Note: Currently, this is restricted to a single level meet
2298 
2299 .keywords: mesh
2300 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2301 @*/
2302 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2303 {
2304   DM_Plex    *mesh = (DM_Plex *) dm->data;
2305   PetscInt      *meet[2];
2306   PetscInt       meetSize, i = 0;
2307   PetscInt       dof, off, p, c, m;
2308   PetscErrorCode ierr;
2309 
2310   PetscFunctionBegin;
2311   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2312   PetscValidPointer(points, 2);
2313   PetscValidPointer(numCoveringPoints, 3);
2314   PetscValidPointer(coveringPoints, 4);
2315   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2316   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2317   /* Copy in cone of first point */
2318   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2319   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2320   for (meetSize = 0; meetSize < dof; ++meetSize) {
2321     meet[i][meetSize] = mesh->cones[off+meetSize];
2322   }
2323   /* Check each successive cone */
2324   for (p = 1; p < numPoints; ++p) {
2325     PetscInt newMeetSize = 0;
2326 
2327     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2328     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2329     for (c = 0; c < dof; ++c) {
2330       const PetscInt point = mesh->cones[off+c];
2331 
2332       for (m = 0; m < meetSize; ++m) {
2333         if (point == meet[i][m]) {
2334           meet[1-i][newMeetSize++] = point;
2335           break;
2336         }
2337       }
2338     }
2339     meetSize = newMeetSize;
2340     i = 1-i;
2341   }
2342   *numCoveringPoints = meetSize;
2343   *coveringPoints    = meet[i];
2344   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2345   PetscFunctionReturn(0);
2346 }
2347 
2348 #undef __FUNCT__
2349 #define __FUNCT__ "DMPlexRestoreMeet"
2350 /*@C
2351   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2352 
2353   Not Collective
2354 
2355   Input Parameters:
2356 + dm - The DMPlex object
2357 . numPoints - The number of input points for the meet
2358 - points - The input points
2359 
2360   Output Parameters:
2361 + numCoveredPoints - The number of points in the meet
2362 - coveredPoints - The points in the meet
2363 
2364   Level: intermediate
2365 
2366 .keywords: mesh
2367 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2368 @*/
2369 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2370 {
2371   PetscErrorCode ierr;
2372 
2373   PetscFunctionBegin;
2374   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2375   PetscValidPointer(coveredPoints, 4);
2376   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2377   PetscFunctionReturn(0);
2378 }
2379 
2380 #undef __FUNCT__
2381 #define __FUNCT__ "DMPlexGetFullMeet"
2382 /*@C
2383   DMPlexGetFullMeet - Get an array for the meet of the set of points
2384 
2385   Not Collective
2386 
2387   Input Parameters:
2388 + dm - The DMPlex object
2389 . numPoints - The number of input points for the meet
2390 - points - The input points
2391 
2392   Output Parameters:
2393 + numCoveredPoints - The number of points in the meet
2394 - coveredPoints - The points in the meet
2395 
2396   Level: intermediate
2397 
2398 .keywords: mesh
2399 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2400 @*/
2401 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2402 {
2403   DM_Plex    *mesh = (DM_Plex *) dm->data;
2404   PetscInt      *offsets, **closures;
2405   PetscInt      *meet[2];
2406   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2407   PetscInt       p, h, c, m;
2408   PetscErrorCode ierr;
2409 
2410   PetscFunctionBegin;
2411   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2412   PetscValidPointer(points, 2);
2413   PetscValidPointer(numCoveredPoints, 3);
2414   PetscValidPointer(coveredPoints, 4);
2415 
2416   ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2417   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2418   ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2419   maxSize = PetscPowInt(mesh->maxConeSize,height);
2420   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2421   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2422 
2423   for (p = 0; p < numPoints; ++p) {
2424     PetscInt closureSize;
2425 
2426     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2427     offsets[p*(height+2)+0] = 0;
2428     for (h = 0; h < height+1; ++h) {
2429       PetscInt pStart, pEnd, i;
2430 
2431       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2432       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2433         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2434           offsets[p*(height+2)+h+1] = i;
2435           break;
2436         }
2437       }
2438       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2439     }
2440     if (offsets[p*(height+2)+height+1] != closureSize) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Total size of closure %D should be %D", offsets[p*(height+2)+height+1], closureSize);
2441   }
2442   for (h = 0; h < height+1; ++h) {
2443     PetscInt dof;
2444 
2445     /* Copy in cone of first point */
2446     dof = offsets[h+1] - offsets[h];
2447     for (meetSize = 0; meetSize < dof; ++meetSize) {
2448       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2449     }
2450     /* Check each successive cone */
2451     for (p = 1; p < numPoints && meetSize; ++p) {
2452       PetscInt newMeetSize = 0;
2453 
2454       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2455       for (c = 0; c < dof; ++c) {
2456         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2457 
2458         for (m = 0; m < meetSize; ++m) {
2459           if (point == meet[i][m]) {
2460             meet[1-i][newMeetSize++] = point;
2461             break;
2462           }
2463         }
2464       }
2465       meetSize = newMeetSize;
2466       i = 1-i;
2467     }
2468     if (meetSize) break;
2469   }
2470   *numCoveredPoints = meetSize;
2471   *coveredPoints    = meet[i];
2472   for (p = 0; p < numPoints; ++p) {
2473     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2474   }
2475   ierr = PetscFree(closures);CHKERRQ(ierr);
2476   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2477   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2478   PetscFunctionReturn(0);
2479 }
2480 
2481 #undef __FUNCT__
2482 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2483 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices)
2484 {
2485   MPI_Comm       comm = ((PetscObject) dm)->comm;
2486   PetscInt       cellDim;
2487   PetscErrorCode ierr;
2488 
2489   PetscFunctionBegin;
2490   PetscValidPointer(numFaceVertices,3);
2491   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2492   switch (cellDim) {
2493   case 0:
2494     *numFaceVertices = 0;
2495     break;
2496   case 1:
2497     *numFaceVertices = 1;
2498     break;
2499   case 2:
2500     switch (numCorners) {
2501     case 3: /* triangle */
2502       *numFaceVertices = 2; /* Edge has 2 vertices */
2503       break;
2504     case 4: /* quadrilateral */
2505       *numFaceVertices = 2; /* Edge has 2 vertices */
2506       break;
2507     case 6: /* quadratic triangle, tri and quad cohesive Lagrange cells */
2508       *numFaceVertices = 3; /* Edge has 3 vertices */
2509       break;
2510     case 9: /* quadratic quadrilateral, quadratic quad cohesive Lagrange cells */
2511       *numFaceVertices = 3; /* Edge has 3 vertices */
2512       break;
2513     default:
2514       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2515     }
2516     break;
2517   case 3:
2518     switch (numCorners) {
2519     case 4: /* tetradehdron */
2520       *numFaceVertices = 3; /* Face has 3 vertices */
2521       break;
2522     case 6: /* tet cohesive cells */
2523       *numFaceVertices = 4; /* Face has 4 vertices */
2524       break;
2525     case 8: /* hexahedron */
2526       *numFaceVertices = 4; /* Face has 4 vertices */
2527       break;
2528     case 9: /* tet cohesive Lagrange cells */
2529       *numFaceVertices = 6; /* Face has 6 vertices */
2530       break;
2531     case 10: /* quadratic tetrahedron */
2532       *numFaceVertices = 6; /* Face has 6 vertices */
2533       break;
2534     case 12: /* hex cohesive Lagrange cells */
2535       *numFaceVertices = 6; /* Face has 6 vertices */
2536       break;
2537     case 18: /* quadratic tet cohesive Lagrange cells */
2538       *numFaceVertices = 6; /* Face has 6 vertices */
2539       break;
2540     case 27: /* quadratic hexahedron, quadratic hex cohesive Lagrange cells */
2541       *numFaceVertices = 9; /* Face has 9 vertices */
2542       break;
2543     default:
2544       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2545     }
2546     break;
2547   default:
2548     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2549   }
2550   PetscFunctionReturn(0);
2551 }
2552 
2553 #undef __FUNCT__
2554 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2555 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency)
2556 {
2557   const PetscInt maxFaceCases = 30;
2558   PetscInt       numFaceCases = 0;
2559   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2560   PetscInt      *off, *adj;
2561   PetscInt      *neighborCells, *tmpClosure;
2562   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2563   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2564   PetscErrorCode ierr;
2565 
2566   PetscFunctionBegin;
2567   /* For parallel partitioning, I think you have to communicate supports */
2568   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2569   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2570   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2571   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2572   if (cEnd - cStart == 0) {
2573     if (numVertices) *numVertices = 0;
2574     if (offsets)     *offsets     = PETSC_NULL;
2575     if (adjacency)   *adjacency   = PETSC_NULL;
2576     PetscFunctionReturn(0);
2577   }
2578   numCells = cEnd - cStart;
2579   /* Setup face recognition */
2580   {
2581     PetscInt cornersSeen[30] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* Could use PetscBT */
2582 
2583     for (c = cStart; c < cEnd; ++c) {
2584       PetscInt corners;
2585 
2586       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2587       if (!cornersSeen[corners]) {
2588         PetscInt nFV;
2589 
2590         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2591         cornersSeen[corners] = 1;
2592         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2593         numFaceVertices[numFaceCases++] = nFV;
2594       }
2595     }
2596   }
2597   maxClosure   = 2*PetscMax(PetscPowInt(maxConeSize,depth),PetscPowInt(maxSupportSize,depth));
2598   maxNeighbors = PetscPowInt(maxConeSize,depth)*PetscPowInt(maxSupportSize,depth);
2599   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2600   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2601   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2602   /* Count neighboring cells */
2603   for (cell = cStart; cell < cEnd; ++cell) {
2604     PetscInt numNeighbors = maxNeighbors, n;
2605 
2606     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2607     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2608     for (n = 0; n < numNeighbors; ++n) {
2609       PetscInt        cellPair[2];
2610       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2611       PetscInt        meetSize    = 0;
2612       const PetscInt *meet        = PETSC_NULL;
2613 
2614       cellPair[0] = cell; cellPair[1] = neighborCells[n];
2615       if (cellPair[0] == cellPair[1]) continue;
2616       if (!found) {
2617         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2618         if (meetSize) {
2619           PetscInt f;
2620 
2621           for (f = 0; f < numFaceCases; ++f) {
2622             if (numFaceVertices[f] == meetSize) {
2623               found = PETSC_TRUE;
2624               break;
2625             }
2626           }
2627         }
2628         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2629       }
2630       if (found) {
2631         ++off[cell-cStart+1];
2632       }
2633     }
2634   }
2635   /* Prefix sum */
2636   for (cell = 1; cell <= numCells; ++cell) {
2637     off[cell] += off[cell-1];
2638   }
2639   if (adjacency) {
2640     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2641     /* Get neighboring cells */
2642     for (cell = cStart; cell < cEnd; ++cell) {
2643       PetscInt numNeighbors = maxNeighbors, n;
2644       PetscInt cellOffset   = 0;
2645 
2646       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2647       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2648       for (n = 0; n < numNeighbors; ++n) {
2649         PetscInt        cellPair[2];
2650         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2651         PetscInt        meetSize    = 0;
2652         const PetscInt *meet        = PETSC_NULL;
2653 
2654         cellPair[0] = cell; cellPair[1] = neighborCells[n];
2655         if (cellPair[0] == cellPair[1]) continue;
2656         if (!found) {
2657           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2658           if (meetSize) {
2659             PetscInt f;
2660 
2661             for (f = 0; f < numFaceCases; ++f) {
2662               if (numFaceVertices[f] == meetSize) {
2663                 found = PETSC_TRUE;
2664                 break;
2665               }
2666             }
2667           }
2668           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2669         }
2670         if (found) {
2671           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2672           ++cellOffset;
2673         }
2674       }
2675     }
2676   }
2677   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2678   if (numVertices) *numVertices = numCells;
2679   if (offsets)     *offsets     = off;
2680   if (adjacency)   *adjacency   = adj;
2681   PetscFunctionReturn(0);
2682 }
2683 
2684 #if defined(PETSC_HAVE_CHACO)
2685 #if defined(PETSC_HAVE_UNISTD_H)
2686 #include <unistd.h>
2687 #endif
2688 /* Chaco does not have an include file */
2689 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2690                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2691                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2692                        int mesh_dims[3], double *goal, int global_method, int local_method,
2693                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2694 
2695 extern int FREE_GRAPH;
2696 
2697 #undef __FUNCT__
2698 #define __FUNCT__ "DMPlexPartition_Chaco"
2699 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2700 {
2701   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2702   MPI_Comm comm = ((PetscObject) dm)->comm;
2703   int nvtxs = numVertices;                /* number of vertices in full graph */
2704   int *vwgts = NULL;                      /* weights for all vertices */
2705   float *ewgts = NULL;                    /* weights for all edges */
2706   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2707   char *outassignname = NULL;             /*  name of assignment output file */
2708   char *outfilename = NULL;               /* output file name */
2709   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2710   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2711   int mesh_dims[3];                       /* dimensions of mesh of processors */
2712   double *goal = NULL;                    /* desired set sizes for each set */
2713   int global_method = 1;                  /* global partitioning algorithm */
2714   int local_method = 1;                   /* local partitioning algorithm */
2715   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2716   int vmax = 200;                         /* how many vertices to coarsen down to? */
2717   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2718   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2719   long seed = 123636512;                  /* for random graph mutations */
2720   short int *assignment;                  /* Output partition */
2721   int fd_stdout, fd_pipe[2];
2722   PetscInt      *points;
2723   PetscMPIInt    commSize;
2724   int            i, v, p;
2725   PetscErrorCode ierr;
2726 
2727   PetscFunctionBegin;
2728   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2729   if (!numVertices) {
2730     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2731     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2732     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2733     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2734     PetscFunctionReturn(0);
2735   }
2736   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2737   for (i = 0; i < start[numVertices]; ++i) {
2738     ++adjacency[i];
2739   }
2740   if (global_method == INERTIAL_METHOD) {
2741     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2742     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2743   }
2744   mesh_dims[0] = commSize;
2745   mesh_dims[1] = 1;
2746   mesh_dims[2] = 1;
2747   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2748   /* Chaco outputs to stdout. We redirect this to a buffer. */
2749   /* TODO: check error codes for UNIX calls */
2750 #if defined(PETSC_HAVE_UNISTD_H)
2751   {
2752     int piperet;
2753     piperet = pipe(fd_pipe);
2754     if (piperet) SETERRQ(comm,PETSC_ERR_SYS,"Could not create pipe");
2755     fd_stdout = dup(1);
2756     close(1);
2757     dup2(fd_pipe[1], 1);
2758   }
2759 #endif
2760   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2761                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2762                    vmax, ndims, eigtol, seed);
2763 #if defined(PETSC_HAVE_UNISTD_H)
2764   {
2765     char msgLog[10000];
2766     int  count;
2767 
2768     fflush(stdout);
2769     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2770     if (count < 0) count = 0;
2771     msgLog[count] = 0;
2772     close(1);
2773     dup2(fd_stdout, 1);
2774     close(fd_stdout);
2775     close(fd_pipe[0]);
2776     close(fd_pipe[1]);
2777     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2778   }
2779 #endif
2780   /* Convert to PetscSection+IS */
2781   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2782   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2783   for (v = 0; v < nvtxs; ++v) {
2784     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2785   }
2786   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2787   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2788   for (p = 0, i = 0; p < commSize; ++p) {
2789     for (v = 0; v < nvtxs; ++v) {
2790       if (assignment[v] == p) points[i++] = v;
2791     }
2792   }
2793   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2794   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2795   if (global_method == INERTIAL_METHOD) {
2796     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2797   }
2798   ierr = PetscFree(assignment);CHKERRQ(ierr);
2799   for (i = 0; i < start[numVertices]; ++i) {
2800     --adjacency[i];
2801   }
2802   PetscFunctionReturn(0);
2803 }
2804 #endif
2805 
2806 #if defined(PETSC_HAVE_PARMETIS)
2807 #undef __FUNCT__
2808 #define __FUNCT__ "DMPlexPartition_ParMetis"
2809 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2810 {
2811   PetscFunctionBegin;
2812   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2813   PetscFunctionReturn(0);
2814 }
2815 #endif
2816 
2817 #undef __FUNCT__
2818 #define __FUNCT__ "DMPlexEnlargePartition"
2819 /* Expand the partition by BFS on the adjacency graph */
2820 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition)
2821 {
2822   PetscHashI      h;
2823   const PetscInt *points;
2824   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2825   PetscInt        pStart, pEnd, part, q;
2826   PetscErrorCode  ierr;
2827 
2828   PetscFunctionBegin;
2829   PetscHashICreate(h);
2830   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2831   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2832   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2833   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2834   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2835   for (part = pStart; part < pEnd; ++part) {
2836     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2837 
2838     PetscHashIClear(h);
2839     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2840     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2841     /* Add all existing points to h */
2842     for (p = 0; p < numPoints; ++p) {
2843       const PetscInt point = points[off+p];
2844       PetscHashIAdd(h, point, 1);
2845     }
2846     PetscHashISize(h, nP);
2847     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2848     /* Add all points in next BFS level */
2849     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2850     for (p = 0; p < numPoints; ++p) {
2851       const PetscInt point = points[off+p];
2852       PetscInt s = start[point], e = start[point+1], a;
2853 
2854       for (a = s; a < e; ++a) {
2855         PetscHashIAdd(h, adjacency[a], 1);
2856       }
2857     }
2858     PetscHashISize(h, numNewPoints);
2859     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2860     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2861     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2862     totPoints += numNewPoints;
2863   }
2864   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2865   PetscHashIDestroy(h);
2866   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2867   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2868   for (part = pStart, q = 0; part < pEnd; ++part) {
2869     PetscInt numPoints, p;
2870 
2871     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2872     for (p = 0; p < numPoints; ++p, ++q) {
2873       newPoints[q] = tmpPoints[part][p];
2874     }
2875     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2876   }
2877   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2878   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2879   PetscFunctionReturn(0);
2880 }
2881 
2882 #undef __FUNCT__
2883 #define __FUNCT__ "DMPlexCreatePartition"
2884 /*
2885   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2886 
2887   Collective on DM
2888 
2889   Input Parameters:
2890   + dm - The DM
2891   . height - The height for points in the partition
2892   - enlarge - Expand each partition with neighbors
2893 
2894   Output Parameters:
2895   + partSection - The PetscSection giving the division of points by partition
2896   . partition - The list of points by partition
2897   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2898   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2899 
2900   Level: developer
2901 
2902 .seealso DMPlexDistribute()
2903 */
2904 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition)
2905 {
2906   PetscMPIInt    size;
2907   PetscErrorCode ierr;
2908 
2909   PetscFunctionBegin;
2910   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2911   *origPartSection = PETSC_NULL;
2912   *origPartition   = PETSC_NULL;
2913   if (size == 1) {
2914     PetscInt *points;
2915     PetscInt  cStart, cEnd, c;
2916 
2917     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2918     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2919     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2920     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2921     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2922     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2923     for (c = cStart; c < cEnd; ++c) {
2924       points[c] = c;
2925     }
2926     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2927     PetscFunctionReturn(0);
2928   }
2929   if (height == 0) {
2930     PetscInt  numVertices;
2931     PetscInt *start     = PETSC_NULL;
2932     PetscInt *adjacency = PETSC_NULL;
2933 
2934     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2935     if (1) {
2936 #if defined(PETSC_HAVE_CHACO)
2937       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2938 #endif
2939     } else {
2940 #if defined(PETSC_HAVE_PARMETIS)
2941       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2942 #endif
2943     }
2944     if (enlarge) {
2945       *origPartSection = *partSection;
2946       *origPartition   = *partition;
2947       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2948     }
2949     ierr = PetscFree(start);CHKERRQ(ierr);
2950     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2951 # if 0
2952   } else if (height == 1) {
2953     /* Build the dual graph for faces and partition the hypergraph */
2954     PetscInt numEdges;
2955 
2956     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2957     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2958     destroyCSR(numEdges, start, adjacency);
2959 #endif
2960   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2961   PetscFunctionReturn(0);
2962 }
2963 
2964 #undef __FUNCT__
2965 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2966 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition)
2967 {
2968   /* const PetscInt  height = 0; */
2969   const PetscInt *partArray;
2970   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2971   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2972   PetscErrorCode  ierr;
2973 
2974   PetscFunctionBegin;
2975   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2976   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2977   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2978   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2979   for (rank = rStart; rank < rEnd; ++rank) {
2980     PetscInt partSize = 0;
2981     PetscInt numPoints, offset, p;
2982 
2983     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2984     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2985     for (p = 0; p < numPoints; ++p) {
2986       PetscInt  point   = partArray[offset+p], closureSize, c;
2987       PetscInt *closure = PETSC_NULL;
2988 
2989       /* TODO Include support for height > 0 case */
2990       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2991       /* Merge into existing points */
2992       if (partSize+closureSize > maxPartSize) {
2993         PetscInt *tmpPoints;
2994 
2995         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2996         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2997         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
2998         ierr = PetscFree(partPoints);CHKERRQ(ierr);
2999         partPoints = tmpPoints;
3000       }
3001       for (c = 0; c < closureSize; ++c) {
3002         partPoints[partSize+c] = closure[c*2];
3003       }
3004       partSize += closureSize;
3005       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3006       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3007     }
3008     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3009   }
3010   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3011   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3012   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3013 
3014   for (rank = rStart; rank < rEnd; ++rank) {
3015     PetscInt partSize = 0, newOffset;
3016     PetscInt numPoints, offset, p;
3017 
3018     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3019     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3020     for (p = 0; p < numPoints; ++p) {
3021       PetscInt  point   = partArray[offset+p], closureSize, c;
3022       PetscInt *closure = PETSC_NULL;
3023 
3024       /* TODO Include support for height > 0 case */
3025       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3026       /* Merge into existing points */
3027       for (c = 0; c < closureSize; ++c) {
3028         partPoints[partSize+c] = closure[c*2];
3029       }
3030       partSize += closureSize;
3031       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3032       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3033     }
3034     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3035     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3036   }
3037   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3038   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3039   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3040   PetscFunctionReturn(0);
3041 }
3042 
3043 #undef __FUNCT__
3044 #define __FUNCT__ "DMPlexDistributeField"
3045 /*
3046   Input Parameters:
3047 . originalSection
3048 , originalVec
3049 
3050   Output Parameters:
3051 . newSection
3052 . newVec
3053 */
3054 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3055 {
3056   PetscSF         fieldSF;
3057   PetscInt       *remoteOffsets, fieldSize;
3058   PetscScalar    *originalValues, *newValues;
3059   PetscErrorCode  ierr;
3060 
3061   PetscFunctionBegin;
3062   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3063 
3064   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3065   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3066   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3067 
3068   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3069   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3070   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3071   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3072   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3073   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3074   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3075   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3076   PetscFunctionReturn(0);
3077 }
3078 
3079 #undef __FUNCT__
3080 #define __FUNCT__ "DMPlexDistribute"
3081 /*@C
3082   DMPlexDistribute - Distributes the mesh and any associated sections.
3083 
3084   Not Collective
3085 
3086   Input Parameter:
3087 + dm  - The original DMPlex object
3088 . partitioner - The partitioning package, or NULL for the default
3089 - overlap - The overlap of partitions, 0 is the default
3090 
3091   Output Parameter:
3092 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3093 
3094   Note: If the mesh was not distributed, the return value is PETSC_NULL
3095 
3096   Level: intermediate
3097 
3098 .keywords: mesh, elements
3099 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3100 @*/
3101 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3102 {
3103   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3104   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3105   const PetscInt height = 0;
3106   PetscInt       dim, numRemoteRanks;
3107   IS             origCellPart,        cellPart,        part;
3108   PetscSection   origCellPartSection, cellPartSection, partSection;
3109   PetscSFNode   *remoteRanks;
3110   PetscSF        partSF, pointSF, coneSF;
3111   ISLocalToGlobalMapping renumbering;
3112   PetscSection   originalConeSection, newConeSection;
3113   PetscInt      *remoteOffsets;
3114   PetscInt      *cones, *newCones, newConesSize;
3115   PetscBool      flg;
3116   PetscMPIInt    rank, numProcs, p;
3117   PetscErrorCode ierr;
3118 
3119   PetscFunctionBegin;
3120   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3121   PetscValidPointer(dmParallel,4);
3122   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3123   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3124   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3125   *dmParallel = PETSC_NULL;
3126   if (numProcs == 1) PetscFunctionReturn(0);
3127 
3128   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3129   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3130   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3131   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3132   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3133   if (!rank) {
3134     numRemoteRanks = numProcs;
3135   } else {
3136     numRemoteRanks = 0;
3137   }
3138   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3139   for (p = 0; p < numRemoteRanks; ++p) {
3140     remoteRanks[p].rank  = p;
3141     remoteRanks[p].index = 0;
3142   }
3143   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3144   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3145   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3146   if (flg) {
3147     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3148     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3149     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3150     if (origCellPart) {
3151       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3152       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3153       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3154     }
3155     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3156   }
3157   /* Close the partition over the mesh */
3158   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3159   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3160   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3161   /* Create new mesh */
3162   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3163   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3164   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3165   pmesh = (DM_Plex *) (*dmParallel)->data;
3166   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3167   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3168   if (flg) {
3169     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3170     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3171     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3172     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3173     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3174     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3175   }
3176   /* Distribute cone section */
3177   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3178   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3179   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3180   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3181   {
3182     PetscInt pStart, pEnd, p;
3183 
3184     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3185     for (p = pStart; p < pEnd; ++p) {
3186       PetscInt coneSize;
3187       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3188       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3189     }
3190   }
3191   /* Communicate and renumber cones */
3192   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3193   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3194   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3195   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3196   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3197   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3198   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3199   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3200   if (flg) {
3201     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3202     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3203     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3204     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3205     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3206   }
3207   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3208   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3209   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3210   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3211   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3212   /* Create supports and stratify sieve */
3213   {
3214     PetscInt pStart, pEnd;
3215 
3216     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3217     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3218   }
3219   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3220   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3221   /* Distribute Coordinates */
3222   {
3223     PetscSection originalCoordSection, newCoordSection;
3224     Vec          originalCoordinates, newCoordinates;
3225     const char  *name;
3226 
3227     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3228     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3229     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3230     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3231     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3232     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3233 
3234     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3235     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3236     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3237   }
3238   /* Distribute labels */
3239   {
3240     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3241     PetscInt   numLabels = 0, l;
3242 
3243     /* Bcast number of labels */
3244     while (next) {++numLabels; next = next->next;}
3245     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3246     next = mesh->labels;
3247     for (l = 0; l < numLabels; ++l) {
3248       DMLabel         newLabel;
3249       const PetscInt *partArray;
3250       char           *name;
3251       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3252       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3253       PetscInt        nameSize, s, p;
3254       PetscBool       isdepth;
3255       size_t          len = 0;
3256 
3257       /* Bcast name (could filter for no points) */
3258       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3259       nameSize = len;
3260       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3261       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3262       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3263       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3264       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3265       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3266       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3267       newLabel->name = name;
3268       /* Bcast numStrata (could filter for no points in stratum) */
3269       if (!rank) {newLabel->numStrata = next->numStrata;}
3270       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3271       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3272                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3273                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3274       /* Bcast stratumValues (could filter for no points in stratum) */
3275       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3276       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3277       /* Find size on each process and Scatter */
3278       if (!rank) {
3279         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3280         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3281         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3282         for (s = 0; s < next->numStrata; ++s) {
3283           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3284             const PetscInt point = next->points[p];
3285             PetscInt       proc;
3286 
3287             for (proc = 0; proc < numProcs; ++proc) {
3288               PetscInt dof, off, pPart;
3289 
3290               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3291               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3292               for (pPart = off; pPart < off+dof; ++pPart) {
3293                 if (partArray[pPart] == point) {
3294                   ++stratumSizes[proc*next->numStrata+s];
3295                   break;
3296                 }
3297               }
3298             }
3299           }
3300         }
3301         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3302       }
3303       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3304       /* Calculate stratumOffsets */
3305       newLabel->stratumOffsets[0] = 0;
3306       for (s = 0; s < newLabel->numStrata; ++s) {
3307         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3308       }
3309       /* Pack points and Scatter */
3310       if (!rank) {
3311         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3312         displs[0] = 0;
3313         for (p = 0; p < numProcs; ++p) {
3314           sendcnts[p] = 0;
3315           for (s = 0; s < next->numStrata; ++s) {
3316             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3317           }
3318           offsets[p]  = displs[p];
3319           displs[p+1] = displs[p] + sendcnts[p];
3320         }
3321         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3322         for (s = 0; s < next->numStrata; ++s) {
3323           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3324             const PetscInt point = next->points[p];
3325             PetscInt       proc;
3326 
3327             for (proc = 0; proc < numProcs; ++proc) {
3328               PetscInt dof, off, pPart;
3329 
3330               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3331               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3332               for (pPart = off; pPart < off+dof; ++pPart) {
3333                 if (partArray[pPart] == point) {
3334                   points[offsets[proc]++] = point;
3335                   break;
3336                 }
3337               }
3338             }
3339           }
3340         }
3341       }
3342       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3343       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3344       ierr = PetscFree(points);CHKERRQ(ierr);
3345       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3346       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3347       /* Renumber points */
3348       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3349       /* Sort points */
3350       for (s = 0; s < newLabel->numStrata; ++s) {
3351         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3352       }
3353       /* Insert into list */
3354       if (newNext) {
3355         newNext->next = newLabel;
3356       } else {
3357         pmesh->labels = newLabel;
3358       }
3359       newNext = newLabel;
3360       if (!rank) {next = next->next;}
3361     }
3362   }
3363   /* Cleanup Partition */
3364   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3365   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3366   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3367   ierr = ISDestroy(&part);CHKERRQ(ierr);
3368   /* Create point SF for parallel mesh */
3369   {
3370     const PetscInt *leaves;
3371     PetscSFNode    *remotePoints, *rowners, *lowners;
3372     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3373     PetscInt        pStart, pEnd;
3374 
3375     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3376     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3377     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3378     for (p=0; p<numRoots; p++) {
3379       rowners[p].rank = -1;
3380       rowners[p].index = -1;
3381     }
3382     if (origCellPart) {
3383       /* Make sure cells in the original partition are not assigned to other procs */
3384       const PetscInt *origCells;
3385 
3386       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3387       for (p = 0; p < numProcs; ++p) {
3388         PetscInt dof, off, d;
3389 
3390         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3391         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3392         for (d = off; d < off+dof; ++d) {
3393           rowners[origCells[d]].rank = p;
3394         }
3395       }
3396       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3397     }
3398     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3399     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3400 
3401     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3402     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3403     for (p = 0; p < numLeaves; ++p) {
3404       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3405         lowners[p].rank = rank;
3406         lowners[p].index = leaves ? leaves[p] : p;
3407       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3408         lowners[p].rank = -2;
3409         lowners[p].index = -2;
3410       }
3411     }
3412     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3413       rowners[p].rank = -3;
3414       rowners[p].index = -3;
3415     }
3416     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3417     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3418     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3419     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3420     for (p = 0; p < numLeaves; ++p) {
3421       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3422       if (lowners[p].rank != rank) ++numGhostPoints;
3423     }
3424     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3425     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3426     for (p = 0, gp = 0; p < numLeaves; ++p) {
3427       if (lowners[p].rank != rank) {
3428         ghostPoints[gp]       = leaves ? leaves[p] : p;
3429         remotePoints[gp].rank  = lowners[p].rank;
3430         remotePoints[gp].index = lowners[p].index;
3431         ++gp;
3432       }
3433     }
3434     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3435     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3436     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3437   }
3438   /* Cleanup */
3439   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3440   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3441   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3442   PetscFunctionReturn(0);
3443 }
3444 
3445 #undef __FUNCT__
3446 #define __FUNCT__ "DMPlexRenumber_Private"
3447 /*
3448   Reasons to renumber:
3449 
3450   1) Permute points, e.g. bandwidth reduction (Renumber)
3451 
3452     a) Must not mix strata
3453 
3454   2) Shift numbers for point insertion (Shift)
3455 
3456     a) Want operation brken into parts so that insertion can be interleaved
3457 
3458   renumbering - An IS which provides the new numbering
3459 */
3460 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3461 {
3462   PetscFunctionBegin;
3463   PetscFunctionReturn(0);
3464 }
3465 
3466 #undef __FUNCT__
3467 #define __FUNCT__ "DMPlexShiftPoint_Private"
3468 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3469 {
3470   if (depth < 0) return p;
3471   /* Cells    */ if (p < depthEnd[depth])   return p;
3472   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3473   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3474   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3475 }
3476 
3477 #undef __FUNCT__
3478 #define __FUNCT__ "DMPlexShiftSizes_Private"
3479 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3480 {
3481   PetscInt      *depthEnd;
3482   PetscInt       depth = 0, d, pStart, pEnd, p;
3483   PetscErrorCode ierr;
3484 
3485   PetscFunctionBegin;
3486   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3487   if (depth < 0) PetscFunctionReturn(0);
3488   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3489   /* Step 1: Expand chart */
3490   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3491   for (d = 0; d <= depth; ++d) {
3492     pEnd += depthShift[d];
3493     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3494   }
3495   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3496   /* Step 2: Set cone and support sizes */
3497   for (d = 0; d <= depth; ++d) {
3498     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3499     for (p = pStart; p < pEnd; ++p) {
3500       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3501       PetscInt size;
3502 
3503       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3504       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3505       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3506       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3507     }
3508   }
3509   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3510   PetscFunctionReturn(0);
3511 }
3512 
3513 #undef __FUNCT__
3514 #define __FUNCT__ "DMPlexShiftPoints_Private"
3515 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3516 {
3517   PetscInt      *depthEnd, *newpoints;
3518   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3519   PetscErrorCode ierr;
3520 
3521   PetscFunctionBegin;
3522   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3523   if (depth < 0) PetscFunctionReturn(0);
3524   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3525   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3526   for (d = 0; d <= depth; ++d) {
3527     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3528   }
3529   /* Step 5: Set cones and supports */
3530   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3531   for (p = pStart; p < pEnd; ++p) {
3532     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3533     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3534 
3535     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3536     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3537     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3538     for (i = 0; i < size; ++i) {
3539       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3540     }
3541     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3542     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3543     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3544     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3545     for (i = 0; i < size; ++i) {
3546       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3547     }
3548     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3549   }
3550   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3551   PetscFunctionReturn(0);
3552 }
3553 
3554 #undef __FUNCT__
3555 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3556 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3557 {
3558   PetscSection   coordSection, newCoordSection;
3559   Vec            coordinates, newCoordinates;
3560   PetscScalar   *coords, *newCoords;
3561   PetscInt      *depthEnd, coordSize;
3562   PetscInt       dim, depth = 0, d, vStart, vEnd, vStartNew, vEndNew, v;
3563   PetscErrorCode ierr;
3564 
3565   PetscFunctionBegin;
3566   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3567   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3568   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3569   for (d = 0; d <= depth; ++d) {
3570     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3571   }
3572   /* Step 8: Convert coordinates */
3573   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3574   ierr = DMPlexGetDepthStratum(dmNew, 0, &vStartNew, &vEndNew);CHKERRQ(ierr);
3575   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
3576   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &newCoordSection);CHKERRQ(ierr);
3577   ierr = PetscSectionSetNumFields(newCoordSection, 1);CHKERRQ(ierr);
3578   ierr = PetscSectionSetFieldComponents(newCoordSection, 0, dim);CHKERRQ(ierr);
3579   ierr = PetscSectionSetChart(newCoordSection, vStartNew, vEndNew);CHKERRQ(ierr);
3580   for (v = vStartNew; v < vEndNew; ++v) {
3581     ierr = PetscSectionSetDof(newCoordSection, v, dim);CHKERRQ(ierr);
3582     ierr = PetscSectionSetFieldDof(newCoordSection, v, 0, dim);CHKERRQ(ierr);
3583   }
3584   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3585   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3586   ierr = PetscSectionGetStorageSize(newCoordSection, &coordSize);CHKERRQ(ierr);
3587   ierr = VecCreate(((PetscObject) dm)->comm, &newCoordinates);CHKERRQ(ierr);
3588   ierr = PetscObjectSetName((PetscObject) newCoordinates, "coordinates");CHKERRQ(ierr);
3589   ierr = VecSetSizes(newCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
3590   ierr = VecSetFromOptions(newCoordinates);CHKERRQ(ierr);
3591   ierr = DMSetCoordinatesLocal(dmNew, newCoordinates);CHKERRQ(ierr);
3592   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3593   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
3594   ierr = VecGetArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3595   for (v = vStart; v < vEnd; ++v) {
3596     PetscInt dof, off, noff, d;
3597 
3598     ierr = PetscSectionGetDof(coordSection, v, &dof);CHKERRQ(ierr);
3599     ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
3600     ierr = PetscSectionGetOffset(newCoordSection, DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift), &noff);CHKERRQ(ierr);
3601     for (d = 0; d < dof; ++d) {
3602       newCoords[noff+d] = coords[off+d];
3603     }
3604   }
3605   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
3606   ierr = VecRestoreArray(newCoordinates, &newCoords);CHKERRQ(ierr);
3607   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3608   PetscFunctionReturn(0);
3609 }
3610 
3611 #undef __FUNCT__
3612 #define __FUNCT__ "DMPlexShiftSF_Private"
3613 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3614 {
3615   PetscInt          *depthEnd;
3616   PetscInt           depth = 0, d;
3617   PetscSF            sfPoint, sfPointNew;
3618   const PetscSFNode *remotePoints;
3619   PetscSFNode       *gremotePoints;
3620   const PetscInt    *localPoints;
3621   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3622   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3623   PetscMPIInt        numProcs;
3624   PetscErrorCode     ierr;
3625 
3626   PetscFunctionBegin;
3627   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3628   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3629   for (d = 0; d <= depth; ++d) {
3630     totShift += depthShift[d];
3631     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3632   }
3633   /* Step 9: Convert pointSF */
3634   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3635   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3636   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3637   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3638   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3639   if (numRoots >= 0) {
3640     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3641     for (l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3642     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3643     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3644     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3645     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3646     for (l = 0; l < numLeaves; ++l) {
3647       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3648       gremotePoints[l].rank  = remotePoints[l].rank;
3649       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3650     }
3651     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3652     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3653   }
3654   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3655   PetscFunctionReturn(0);
3656 }
3657 
3658 #undef __FUNCT__
3659 #define __FUNCT__ "DMPlexShiftLabels_Private"
3660 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3661 {
3662   PetscSF        sfPoint;
3663   DMLabel        vtkLabel, ghostLabel;
3664   PetscInt      *depthEnd;
3665   const PetscSFNode *leafRemote;
3666   const PetscInt    *leafLocal;
3667   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3668   PetscMPIInt    rank;
3669   PetscErrorCode ierr;
3670 
3671   PetscFunctionBegin;
3672   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3673   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3674   for (d = 0; d <= depth; ++d) {
3675     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3676   }
3677   /* Step 10: Convert labels */
3678   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3679   for (l = 0; l < numLabels; ++l) {
3680     DMLabel         label, newlabel;
3681     const char     *lname;
3682     PetscBool       isDepth;
3683     IS              valueIS;
3684     const PetscInt *values;
3685     PetscInt        numValues, val;
3686 
3687     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3688     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3689     if (isDepth) continue;
3690     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3691     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3692     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3693     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3694     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3695     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3696     for (val = 0; val < numValues; ++val) {
3697       IS              pointIS;
3698       const PetscInt *points;
3699       PetscInt        numPoints, p;
3700 
3701       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3702       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3703       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3704       for (p = 0; p < numPoints; ++p) {
3705         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3706 
3707         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3708       }
3709       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3710       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3711     }
3712     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3713     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3714   }
3715   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3716   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3717   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3718   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3719   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3720   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3721   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3722   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3723   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3724   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3725   for (l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3726     for (; c < leafLocal[l] && c < cEnd; ++c) {
3727       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3728     }
3729     if (leafLocal[l] >= cEnd) break;
3730     if (leafRemote[l].rank == rank) {
3731       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3732     } else {
3733       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3734     }
3735   }
3736   for (; c < cEnd; ++c) {
3737     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3738   }
3739   if (0) {
3740     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3741     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3742     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3743   }
3744   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3745   for (f = fStart; f < fEnd; ++f) {
3746     PetscInt numCells;
3747 
3748     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3749     if (numCells < 2) {
3750       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3751     } else {
3752       const PetscInt *cells = PETSC_NULL;
3753       PetscInt        vA, vB;
3754 
3755       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3756       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3757       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3758       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3759     }
3760   }
3761   if (0) {
3762     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3763     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3764     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3765   }
3766   PetscFunctionReturn(0);
3767 }
3768 
3769 #undef __FUNCT__
3770 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3771 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3772 {
3773   DMLabel         label;
3774   IS              valueIS;
3775   const PetscInt *values;
3776   PetscInt       *depthShift;
3777   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3778   PetscErrorCode  ierr;
3779 
3780   PetscFunctionBegin;
3781   /* Count ghost cells */
3782   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3783   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3784   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3785   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3786   *numGhostCells = 0;
3787   for (fs = 0; fs < numFS; ++fs) {
3788     PetscInt numBdFaces;
3789 
3790     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3791     *numGhostCells += numBdFaces;
3792   }
3793   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3794   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3795   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3796   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3797   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3798   /* Step 3: Set cone/support sizes for new points */
3799   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3800   for (c = cEnd; c < cEnd + *numGhostCells; ++c) {
3801     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3802   }
3803   for (fs = 0; fs < numFS; ++fs) {
3804     IS              faceIS;
3805     const PetscInt *faces;
3806     PetscInt        numFaces, f;
3807 
3808     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3809     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3810     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3811     for (f = 0; f < numFaces; ++f) {
3812       PetscInt size;
3813 
3814       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3815       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3816       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3817     }
3818     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3819     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3820   }
3821   /* Step 4: Setup ghosted DM */
3822   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3823   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3824   /* Step 6: Set cones and supports for new points */
3825   ghostCell = cEnd;
3826   for (fs = 0; fs < numFS; ++fs) {
3827     IS              faceIS;
3828     const PetscInt *faces;
3829     PetscInt        numFaces, f;
3830 
3831     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3832     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3833     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3834     for (f = 0; f < numFaces; ++f, ++ghostCell) {
3835       PetscInt newFace = faces[f] + *numGhostCells;
3836 
3837       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3838       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3839     }
3840     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3841     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3842   }
3843   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3844   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3845   /* Step 7: Stratify */
3846   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3847   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3848   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3849   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3850   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3851   PetscFunctionReturn(0);
3852 }
3853 
3854 #undef __FUNCT__
3855 #define __FUNCT__ "DMPlexConstructGhostCells"
3856 /*@C
3857   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3858 
3859   Collective on dm
3860 
3861   Input Parameters:
3862 + dm - The original DM
3863 - labelName - The label specifying the boundary faces (this could be auto-generated)
3864 
3865   Output Parameters:
3866 + numGhostCells - The number of ghost cells added to the DM
3867 - dmGhosted - The new DM
3868 
3869   Level: developer
3870 
3871 .seealso: DMCreate()
3872 */
3873 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3874 {
3875   DM             gdm;
3876   PetscInt       dim;
3877   PetscErrorCode ierr;
3878 
3879   PetscFunctionBegin;
3880   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3881   PetscValidPointer(numGhostCells, 3);
3882   PetscValidPointer(dmGhosted, 4);
3883   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3884   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3885   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3886   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3887   switch (dim) {
3888   case 2:
3889     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3890     break;
3891   default:
3892     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3893   }
3894   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3895   *dmGhosted = gdm;
3896   PetscFunctionReturn(0);
3897 }
3898 
3899 #undef __FUNCT__
3900 #define __FUNCT__ "DMPlexConstructCohesiveCells_Private"
3901 PetscErrorCode DMPlexConstructCohesiveCells_Private(DM dm, const char labelName[], DM sdm)
3902 {
3903   MPI_Comm        comm = ((PetscObject) dm)->comm;
3904   DMLabel         label;
3905   IS              valueIS, *pointIS;
3906   const PetscInt *values, **splitPoints;
3907   PetscSection    coordSection;
3908   Vec             coordinates;
3909   PetscScalar    *coords;
3910   PetscInt       *depthShift, *depthOffset, *pMaxNew, *numSplitPoints, *coneNew, *supportNew;
3911   PetscInt        shift = 100, depth = 0, dep, dim, d, numSP = 0, sp, maxConeSize, maxSupportSize, numLabels, p, v;
3912   PetscErrorCode  ierr;
3913 
3914   PetscFunctionBegin;
3915   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3916   /* Count split points and add cohesive cells */
3917   ierr = DMPlexGetLabel(dm, labelName, &label);CHKERRQ(ierr);
3918   if (label) {
3919     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3920     ierr = ISGetLocalSize(valueIS, &numSP);CHKERRQ(ierr);
3921     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3922   }
3923   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3924   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3925   ierr = PetscMalloc5(depth+1,PetscInt,&depthShift,depth+1,PetscInt,&depthOffset,depth+1,PetscInt,&pMaxNew,maxConeSize*3,PetscInt,&coneNew,maxSupportSize,PetscInt,&supportNew);CHKERRQ(ierr);
3926   ierr = PetscMalloc3(depth+1,IS,&pointIS,depth+1,PetscInt,&numSplitPoints,depth+1,const PetscInt*,&splitPoints);CHKERRQ(ierr);
3927   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3928   for(d = 0; d <= depth; ++d) {
3929     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &pMaxNew[d]);CHKERRQ(ierr);
3930     numSplitPoints[d] = 0;
3931     splitPoints[d]    = PETSC_NULL;
3932     pointIS[d]        = PETSC_NULL;
3933   }
3934   for(sp = 0; sp < numSP; ++sp) {
3935     const PetscInt dep = values[sp];
3936 
3937     if ((dep < 0) || (dep > depth)) continue;
3938     ierr = DMLabelGetStratumSize(label, dep, &depthShift[dep]);CHKERRQ(ierr);
3939     ierr = DMLabelGetStratumIS(label, dep, &pointIS[dep]);CHKERRQ(ierr);
3940     if (pointIS[dep]) {
3941       ierr = ISGetLocalSize(pointIS[dep], &numSplitPoints[dep]);CHKERRQ(ierr);
3942       ierr = ISGetIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);
3943     }
3944   }
3945   if (depth >= 0) {
3946     /* Calculate number of additional points */
3947     depthShift[depth] = depthShift[depth-1]; /* There is a cohesive cell for every split face   */
3948     depthShift[1]    += depthShift[0];       /* There is a cohesive edge for every split vertex */
3949     /* Calculate hybrid bound for each dimension */
3950     pMaxNew[0]       += depthShift[depth];
3951     if (depth > 1) {pMaxNew[dim-1] += depthShift[depth] + depthShift[0];}
3952     if (depth > 2) {pMaxNew[1]     += depthShift[depth] + depthShift[0] + depthShift[dim-1];}
3953     /* Calculate point offset for each dimension */
3954     depthOffset[depth] = 0;
3955     depthOffset[0]     = depthOffset[depth] + depthShift[depth];
3956     if (depth > 1) {depthOffset[dim-1] = depthOffset[0]     + depthShift[0];}
3957     if (depth > 2) {depthOffset[1]     = depthOffset[dim-1] + depthShift[dim-1];}
3958   }
3959   ierr = DMPlexShiftSizes_Private(dm, depthShift, sdm);CHKERRQ(ierr);
3960   /* Step 3: Set cone/support sizes for new points */
3961   for(dep = 0; dep <= depth; ++dep) {
3962     for(p = 0; p < numSplitPoints[dep]; ++p) {
3963       const PetscInt  oldp   = splitPoints[dep][p];
3964       const PetscInt  newp   = depthOffset[dep] + oldp;
3965       const PetscInt  splitp = pMaxNew[dep] + p;
3966       const PetscInt *support;
3967       PetscInt        coneSize, supportSize, q, e;
3968 
3969       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
3970       ierr = DMPlexSetConeSize(sdm, splitp, coneSize);CHKERRQ(ierr);
3971       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
3972       ierr = DMPlexSetSupportSize(sdm, splitp, supportSize);CHKERRQ(ierr);
3973       if (dep == depth-1) {
3974         const PetscInt ccell = pMaxNew[depth] + p;
3975         /* Add cohesive cells, they are prisms */
3976         ierr = DMPlexSetConeSize(sdm, ccell, 2 + coneSize);CHKERRQ(ierr);
3977       } else if (dep == 0) {
3978         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
3979 
3980         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
3981         /* Split old vertex: Edges in old split faces and new cohesive edge */
3982         for(e = 0, q = 0; e < supportSize; ++e) {
3983           PetscInt val;
3984 
3985           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3986           if ((val == 1) || (val == (shift + 1))) ++q;
3987         }
3988         ierr = DMPlexSetSupportSize(sdm, newp, q+1);CHKERRQ(ierr);
3989         /* Split new vertex: Edges in new split faces and new cohesive edge */
3990         for(e = 0, q = 0; e < supportSize; ++e) {
3991           PetscInt val;
3992 
3993           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
3994           if ((val == 1) || (val == -(shift + 1))) ++q;
3995         }
3996         ierr = DMPlexSetSupportSize(sdm, splitp, q+1);CHKERRQ(ierr);
3997         /* Add cohesive edges */
3998         ierr = DMPlexSetConeSize(sdm, cedge, 2);CHKERRQ(ierr);
3999         /* Punt for now on support, you loop over closure, extract faces, check which ones are in the label */
4000       } else if (dep == dim-2) {
4001         ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4002         /* Split old edge: Faces in positive side cells and old split faces */
4003         for(e = 0, q = 0; e < supportSize; ++e) {
4004           PetscInt val;
4005 
4006           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4007           if ((val == dim-1) || (val == (shift + dim-1))) ++q;
4008         }
4009         ierr = DMPlexSetSupportSize(sdm, newp, q);CHKERRQ(ierr);
4010         /* Split new edge: Faces in negative side cells and new split faces */
4011         for(e = 0, q = 0; e < supportSize; ++e) {
4012           PetscInt val;
4013 
4014           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4015           if ((val == dim-1) || (val == -(shift + dim-1))) ++q;
4016         }
4017         ierr = DMPlexSetSupportSize(sdm, splitp, q);CHKERRQ(ierr);
4018       }
4019     }
4020   }
4021   /* Step 4: Setup split DM */
4022   ierr = DMSetUp(sdm);CHKERRQ(ierr);
4023   ierr = DMPlexShiftPoints_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4024   /* Step 6: Set cones and supports for new points */
4025   for(dep = 0; dep <= depth; ++dep) {
4026     for(p = 0; p < numSplitPoints[dep]; ++p) {
4027       const PetscInt  oldp   = splitPoints[dep][p];
4028       const PetscInt  newp   = depthOffset[dep] + oldp;
4029       const PetscInt  splitp = pMaxNew[dep] + p;
4030       const PetscInt *cone, *support;
4031       PetscInt        coneSize, supportSize, q, v, e, s;
4032 
4033       ierr = DMPlexGetConeSize(dm, oldp, &coneSize);CHKERRQ(ierr);
4034       ierr = DMPlexGetCone(dm, oldp, &cone);CHKERRQ(ierr);
4035       ierr = DMPlexGetSupportSize(dm, oldp, &supportSize);CHKERRQ(ierr);
4036       ierr = DMPlexGetSupport(dm, oldp, &support);CHKERRQ(ierr);
4037       if (dep == depth-1) {
4038         const PetscInt  ccell = pMaxNew[depth] + p;
4039         const PetscInt *supportF;
4040 
4041         /* Split face:       copy in old face to new face to start */
4042         ierr = DMPlexGetSupport(sdm, newp,  &supportF);CHKERRQ(ierr);
4043         ierr = DMPlexSetSupport(sdm, splitp, supportF);CHKERRQ(ierr);
4044         /* Split old face:   old vertices/edges in cone so no change */
4045         /* Split new face:   new vertices/edges in cone */
4046         for(q = 0; q < coneSize; ++q) {
4047           ierr = PetscFindInt(cone[q], numSplitPoints[dim-2], splitPoints[dim-2], &v);CHKERRQ(ierr);
4048           coneNew[2+q] = pMaxNew[dim-2] + v;
4049         }
4050         ierr = DMPlexSetCone(sdm, splitp, &coneNew[2]);CHKERRQ(ierr);
4051         /* Cohesive cell:    Old and new split face, then new cohesive edges */
4052         coneNew[0] = newp;
4053         coneNew[1] = splitp;
4054         for(q = 0; q < coneSize; ++q) {
4055           coneNew[2+q] = (pMaxNew[1] - pMaxNew[dim-2]) + (depthShift[1] - depthShift[0]) + coneNew[2+q];
4056         }
4057         ierr = DMPlexSetCone(sdm, ccell, coneNew);CHKERRQ(ierr);
4058 
4059 
4060         for(s = 0; s < supportSize; ++s) {
4061           PetscInt val;
4062 
4063           ierr = DMLabelGetValue(label, support[s], &val);CHKERRQ(ierr);
4064           if (val < 0) {
4065             const PetscInt *scone;
4066             PetscInt        sconeSize, sc;
4067 
4068             /* Split old face:   Replace negative side cell with cohesive cell */
4069             ierr = DMPlexInsertSupport(sdm, newp, s, ccell);CHKERRQ(ierr);
4070           } else {
4071             /* Split new face:   Replace positive side cell with cohesive cell */
4072             ierr = DMPlexInsertSupport(sdm, splitp, s, ccell);CHKERRQ(ierr);
4073           }
4074         }
4075       } else if (dep == 0) {
4076         const PetscInt cedge = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4077 
4078         /* Split old vertex: Edges in old split faces and new cohesive edge */
4079         for(e = 0, q = 0; e < supportSize; ++e) {
4080           PetscInt val;
4081 
4082           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4083           if ((val == 1) || (val == (shift + 1))) {
4084             supportNew[q++] = depthOffset[1] + support[e];
4085           }
4086         }
4087         supportNew[q] = cedge;
4088         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4089         /* Split new vertex: Edges in new split faces and new cohesive edge */
4090         for(e = 0, q = 0; e < supportSize; ++e) {
4091           PetscInt val, edge;
4092 
4093           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4094           if (val == 1) {
4095             ierr = PetscFindInt(support[e], numSplitPoints[1], splitPoints[1], &edge);CHKERRQ(ierr);
4096             if (edge < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Edge %d is not a split edge", support[e]);
4097             supportNew[q++] = pMaxNew[1] + edge;
4098           } else if (val == -(shift + 1)) {
4099             supportNew[q++] = depthOffset[1] + support[e];
4100           }
4101         }
4102         supportNew[q] = cedge;
4103         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4104         /* Cohesive edge:    Old and new split vertex, punting on support */
4105         coneNew[0] = newp;
4106         coneNew[1] = splitp;
4107         ierr = DMPlexSetCone(sdm, cedge, coneNew);CHKERRQ(ierr);
4108       } else if (dep == dim-2) {
4109         /* Split old edge:   old vertices in cone so no change */
4110         /* Split new edge:   new vertices in cone */
4111         for(q = 0; q < coneSize; ++q) {
4112           ierr = PetscFindInt(cone[q], numSplitPoints[dim-3], splitPoints[dim-3], &v);CHKERRQ(ierr);
4113           coneNew[q] = pMaxNew[dim-3] + v;
4114         }
4115         ierr = DMPlexSetCone(sdm, splitp, coneNew);CHKERRQ(ierr);
4116         /* Split old edge: Faces in positive side cells and old split faces */
4117         for(e = 0, q = 0; e < supportSize; ++e) {
4118           PetscInt val;
4119 
4120           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4121           if ((val == dim-1) || (val == (shift + dim-1))) {
4122             supportNew[q++] = depthOffset[dim-1] + support[e];
4123           }
4124         }
4125         ierr = DMPlexSetSupport(sdm, newp, supportNew);CHKERRQ(ierr);
4126         /* Split new edge: Faces in negative side cells and new split faces */
4127         for(e = 0, q = 0; e < supportSize; ++e) {
4128           PetscInt val, face;
4129 
4130           ierr = DMLabelGetValue(label, support[e], &val);CHKERRQ(ierr);
4131           if (val == dim-1) {
4132             ierr = PetscFindInt(support[e], numSplitPoints[dim-1], splitPoints[dim-1], &face);CHKERRQ(ierr);
4133             if (face < 0) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Face %d is not a split face", support[e]);
4134             supportNew[q++] = pMaxNew[dim-1] + face;
4135           } else if (val == -(shift + dim-1)) {
4136             supportNew[q++] = depthOffset[dim-1] + support[e];
4137           }
4138         }
4139         ierr = DMPlexSetSupport(sdm, splitp, supportNew);CHKERRQ(ierr);
4140       }
4141     }
4142   }
4143   /* Step 6b: Replace split points in negative side cones */
4144   for(sp = 0; sp < numSP; ++sp) {
4145     PetscInt        dep = values[sp];
4146     IS              pIS;
4147     PetscInt        numPoints;
4148     const PetscInt *points;
4149 
4150     if (dep >= 0) continue;
4151     ierr = DMLabelGetStratumIS(label, dep, &pIS);CHKERRQ(ierr);
4152     if (!pIS) continue;
4153     dep  = -dep - shift;
4154     ierr = ISGetLocalSize(pIS, &numPoints);CHKERRQ(ierr);
4155     ierr = ISGetIndices(pIS, &points);CHKERRQ(ierr);
4156     for(p = 0; p < numPoints; ++p) {
4157       const PetscInt  oldp   = points[p];
4158       const PetscInt  newp   = depthOffset[dep] + oldp;
4159       const PetscInt  splitp = pMaxNew[dep] + p;
4160       const PetscInt *cone;
4161       PetscInt        coneSize, c;
4162       PetscBool       replaced = PETSC_FALSE;
4163 
4164       /* Negative edge: replace split vertex */
4165       /* Negative cell: replace split face */
4166       ierr = DMPlexGetConeSize(sdm, newp, &coneSize);CHKERRQ(ierr);
4167       ierr = DMPlexGetCone(sdm, newp, &cone);CHKERRQ(ierr);
4168       for(c = 0; c < coneSize; ++c) {
4169         const PetscInt coldp = cone[c] - depthOffset[dep-1];
4170         PetscInt       csplitp, cp, val;
4171 
4172         ierr = DMLabelGetValue(label, coldp, &val);CHKERRQ(ierr);
4173         if (val == dep-1) {
4174           ierr = PetscFindInt(coldp, numSplitPoints[dep-1], splitPoints[dep-1], &cp);CHKERRQ(ierr);
4175           if (cp < 0) SETERRQ2(comm, PETSC_ERR_ARG_WRONG, "Point %d is not a split point of dimension %d", oldp, dep-1);
4176           csplitp = pMaxNew[dep-1] + cp;
4177           ierr = DMPlexInsertCone(sdm, newp, c, csplitp);CHKERRQ(ierr);
4178           replaced = PETSC_TRUE;
4179         }
4180       }
4181       if (!replaced) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "The cone of point %d does not contain split points", oldp);
4182     }
4183     ierr = ISRestoreIndices(pIS, &points);CHKERRQ(ierr);
4184     ierr = ISDestroy(&pIS);CHKERRQ(ierr);
4185   }
4186   /* Step 7: Stratify */
4187   ierr = DMPlexStratify(sdm);CHKERRQ(ierr);
4188   /* Step 8: Coordinates */
4189   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4190   ierr = DMPlexGetCoordinateSection(sdm, &coordSection);CHKERRQ(ierr);
4191   ierr = DMGetCoordinatesLocal(sdm, &coordinates);CHKERRQ(ierr);
4192   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4193   for(v = 0; v < (numSplitPoints ? numSplitPoints[0] : 0); ++v) {
4194     const PetscInt newp   = depthOffset[0] + splitPoints[0][v];
4195     const PetscInt splitp = pMaxNew[0] + v;
4196     PetscInt       dof, off, soff, d;
4197 
4198     ierr = PetscSectionGetDof(coordSection, newp, &dof);CHKERRQ(ierr);
4199     ierr = PetscSectionGetOffset(coordSection, newp, &off);CHKERRQ(ierr);
4200     ierr = PetscSectionGetOffset(coordSection, splitp, &soff);CHKERRQ(ierr);
4201     for(d = 0; d < dof; ++d) {
4202       coords[soff+d] = coords[off+d];
4203     }
4204   }
4205   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4206   /* Step 9: SF, if I can figure this out we can split the mesh in parallel */
4207   ierr = DMPlexShiftSF_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4208   /* Step 10: Labels */
4209   ierr = DMPlexShiftLabels_Private(dm, depthShift, sdm);CHKERRQ(ierr);
4210   ierr = DMPlexGetNumLabels(sdm, &numLabels);CHKERRQ(ierr);
4211   for (dep = 0; dep <= depth; ++dep) {
4212     for (p = 0; p < numSplitPoints[dep]; ++p) {
4213       const PetscInt newp   = depthOffset[dep] + splitPoints[dep][p];
4214       const PetscInt splitp = pMaxNew[dep] + p;
4215       PetscInt       l;
4216 
4217       for (l = 0; l < numLabels; ++l) {
4218         DMLabel     label;
4219         const char *lname;
4220         PetscInt    val;
4221 
4222         ierr = DMPlexGetLabelName(sdm, l, &lname);CHKERRQ(ierr);
4223         ierr = DMPlexGetLabel(sdm, lname, &label);CHKERRQ(ierr);
4224         ierr = DMLabelGetValue(label, newp, &val);CHKERRQ(ierr);
4225         if (val >= 0) {
4226           ierr = DMLabelSetValue(label, splitp, val);CHKERRQ(ierr);
4227           if (dep == 0) {
4228             const PetscInt cedge  = pMaxNew[1] + (depthShift[1] - depthShift[0]) + p;
4229             ierr = DMLabelSetValue(label, cedge, val);CHKERRQ(ierr);
4230           }
4231         }
4232       }
4233     }
4234   }
4235   for (sp = 0; sp < numSP; ++sp) {
4236     const PetscInt dep = values[sp];
4237 
4238     if ((dep < 0) || (dep > depth)) continue;
4239     if (pointIS[dep]) {ierr = ISRestoreIndices(pointIS[dep], &splitPoints[dep]);CHKERRQ(ierr);}
4240     ierr = ISDestroy(&pointIS[dep]);CHKERRQ(ierr);
4241   }
4242   if (label) {
4243     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
4244     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
4245   }
4246   ierr = PetscFree5(depthShift, depthOffset, pMaxNew, coneNew, supportNew);CHKERRQ(ierr);
4247   ierr = PetscFree3(pointIS, numSplitPoints, splitPoints);CHKERRQ(ierr);
4248   PetscFunctionReturn(0);
4249 }
4250 
4251 #undef __FUNCT__
4252 #define __FUNCT__ "DMPlexConstructCohesiveCells"
4253 /*@C
4254   DMPlexConstructCohesiveCells - Construct cohesive cells which split the face along an internal interface
4255 
4256   Collective on dm
4257 
4258   Input Parameters:
4259 + dm - The original DM
4260 - labelName - The label specifying the boundary faces (this could be auto-generated)
4261 
4262   Output Parameters:
4263 - dmSplit - The new DM
4264 
4265   Level: developer
4266 
4267 .seealso: DMCreate()
4268 */
4269 PetscErrorCode DMPlexConstructCohesiveCells(DM dm, const char labelName[], DM *dmSplit)
4270 {
4271   DM             sdm;
4272   PetscInt       dim;
4273   PetscErrorCode ierr;
4274 
4275   PetscFunctionBegin;
4276   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
4277   PetscValidPointer(dmSplit, 4);
4278   ierr = DMCreate(((PetscObject) dm)->comm, &sdm);CHKERRQ(ierr);
4279   ierr = DMSetType(sdm, DMPLEX);CHKERRQ(ierr);
4280   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4281   ierr = DMPlexSetDimension(sdm, dim);CHKERRQ(ierr);
4282   switch(dim) {
4283   case 2:
4284   case 3:
4285     ierr = DMPlexConstructCohesiveCells_Private(dm, labelName, sdm);CHKERRQ(ierr);
4286     break;
4287   default:
4288     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct cohesive cells for dimension %d", dim);
4289   }
4290   *dmSplit = sdm;
4291   PetscFunctionReturn(0);
4292 }
4293 
4294 #undef __FUNCT__
4295 #define __FUNCT__ "DMLabelCohesiveComplete"
4296 PetscErrorCode DMLabelCohesiveComplete(DM dm, DMLabel label)
4297 {
4298   IS              dimIS;
4299   const PetscInt *points;
4300   PetscInt        shift = 100, dim, dep, cStart, cEnd, numPoints, p, val;
4301   PetscErrorCode  ierr;
4302 
4303   PetscFunctionBegin;
4304   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4305   /* Cell orientation for face gives the side of the fault */
4306   ierr = DMLabelGetStratumIS(label, dim-1, &dimIS);CHKERRQ(ierr);
4307   if (!dimIS) PetscFunctionReturn(0);
4308   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4309   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4310   for(p = 0; p < numPoints; ++p) {
4311     const PetscInt *support;
4312     PetscInt        supportSize, s;
4313 
4314     ierr = DMPlexGetSupportSize(dm, points[p], &supportSize);CHKERRQ(ierr);
4315     if (supportSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Split face %d has %d != 2 supports", points[p], supportSize);
4316     ierr = DMPlexGetSupport(dm, points[p], &support);CHKERRQ(ierr);
4317     for(s = 0; s < supportSize; ++s) {
4318       const PetscInt *cone, *ornt;
4319       PetscInt        coneSize, c;
4320       PetscBool       pos = PETSC_TRUE;
4321 
4322       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
4323       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
4324       ierr = DMPlexGetConeOrientation(dm, support[s], &ornt);CHKERRQ(ierr);
4325       for(c = 0; c < coneSize; ++c) {
4326         if (cone[c] == points[p]) {
4327           if (ornt[c] >= 0) {
4328             ierr = DMLabelSetValue(label, support[s],   shift+dim);CHKERRQ(ierr);
4329           } else {
4330             ierr = DMLabelSetValue(label, support[s], -(shift+dim));CHKERRQ(ierr);
4331             pos  = PETSC_FALSE;
4332           }
4333           break;
4334         }
4335       }
4336       if (c == coneSize) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cell split face %d support does not have it in the cone", points[p]);
4337       /* Put faces touching the fault in the label */
4338       for(c = 0; c < coneSize; ++c) {
4339         const PetscInt point = cone[c];
4340 
4341         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4342         if (val == -1) {
4343           PetscInt *closure = PETSC_NULL;
4344           PetscInt  closureSize, cl;
4345 
4346           ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4347           for (cl = 0; cl < closureSize*2; cl += 2) {
4348             const PetscInt clp = closure[cl];
4349 
4350             ierr = DMLabelGetValue(label, clp, &val);CHKERRQ(ierr);
4351             if ((val >= 0) && (val < dim-1)) {
4352               ierr = DMLabelSetValue(label, point, pos == PETSC_TRUE ? shift+dim-1 : -(shift+dim-1));CHKERRQ(ierr);
4353               break;
4354             }
4355           }
4356           ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4357         }
4358       }
4359     }
4360   }
4361   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4362   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4363   /* Search for other cells/faces/edges connected to the fault by a vertex */
4364   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4365   ierr = DMLabelGetStratumIS(label, 0, &dimIS);CHKERRQ(ierr);
4366   if (!dimIS) PetscFunctionReturn(0);
4367   ierr = ISGetLocalSize(dimIS, &numPoints);CHKERRQ(ierr);
4368   ierr = ISGetIndices(dimIS, &points);CHKERRQ(ierr);
4369   for(p = 0; p < numPoints; ++p) {
4370     PetscInt *star = PETSC_NULL;
4371     PetscInt  starSize, s;
4372     PetscInt  again = 1; /* 0: Finished 1: Keep iterating after a change 2: No change */
4373 
4374     /* First mark cells connected to the fault */
4375     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4376     while (again) {
4377       if (again > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Could not classify all cells connected to the fault");
4378       again = 0;
4379       for (s = 0; s < starSize*2; s += 2) {
4380         const PetscInt  point = star[s];
4381         const PetscInt *cone;
4382         PetscInt        coneSize, c;
4383 
4384         if ((point < cStart) || (point >= cEnd)) continue;
4385         ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4386         if (val != -1) continue;
4387         again = 2;
4388         ierr = DMPlexGetConeSize(dm, point, &coneSize);CHKERRQ(ierr);
4389         ierr = DMPlexGetCone(dm, point, &cone);CHKERRQ(ierr);
4390         for(c = 0; c < coneSize; ++c) {
4391           ierr = DMLabelGetValue(label, cone[c], &val);CHKERRQ(ierr);
4392           if (val != -1) {
4393             if (abs(val) < shift) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Face %d on cell %d has an invalid label %d", cone[c], point, val);
4394             if (val > 0) {
4395               ierr = DMLabelSetValue(label, point,   shift+dim);CHKERRQ(ierr);
4396             } else {
4397               ierr = DMLabelSetValue(label, point, -(shift+dim));CHKERRQ(ierr);
4398             }
4399             again = 1;
4400             break;
4401           }
4402         }
4403       }
4404     }
4405     /* Classify the rest by cell membership */
4406     for (s = 0; s < starSize*2; s += 2) {
4407       const PetscInt point = star[s];
4408 
4409       ierr = DMLabelGetValue(label, point, &val);CHKERRQ(ierr);
4410       if (val == -1) {
4411         PetscInt *sstar = PETSC_NULL;
4412         PetscInt  sstarSize, ss;
4413         PetscBool marked = PETSC_FALSE;
4414 
4415         ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4416         for (ss = 0; ss < sstarSize*2; ss += 2) {
4417           const PetscInt spoint = sstar[ss];
4418 
4419           if ((spoint < cStart) || (spoint >= cEnd)) continue;
4420           ierr = DMLabelGetValue(label, spoint, &val);CHKERRQ(ierr);
4421           if (val == -1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Cell %d in star of %d does not have a valid label", spoint, point);
4422           ierr = DMPlexGetLabelValue(dm, "depth", point, &dep);CHKERRQ(ierr);
4423           if (val > 0) {
4424             ierr = DMLabelSetValue(label, point,   shift+dep);CHKERRQ(ierr);
4425           } else {
4426             ierr = DMLabelSetValue(label, point, -(shift+dep));CHKERRQ(ierr);
4427           }
4428           marked = PETSC_TRUE;
4429           break;
4430         }
4431         ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_FALSE, &sstarSize, &sstar);CHKERRQ(ierr);
4432         if (!marked) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d could not be classified", point);
4433       }
4434     }
4435     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
4436   }
4437   ierr = ISRestoreIndices(dimIS, &points);CHKERRQ(ierr);
4438   ierr = ISDestroy(&dimIS);CHKERRQ(ierr);
4439   PetscFunctionReturn(0);
4440 }
4441 
4442 #undef __FUNCT__
4443 #define __FUNCT__ "DMPlexInterpolate_2D"
4444 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
4445 {
4446   DM             idm;
4447   DM_Plex       *mesh;
4448   PetscHashIJ    edgeTable;
4449   PetscInt      *off;
4450   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4451   PetscInt       numEdges, firstEdge, edge, e;
4452   PetscErrorCode ierr;
4453 
4454   PetscFunctionBegin;
4455   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4456   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4457   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4458   numCells    = cEnd - cStart;
4459   numVertices = vEnd - vStart;
4460   firstEdge   = numCells + numVertices;
4461   numEdges    = 0 ;
4462   /* Count edges using algorithm from CreateNeighborCSR */
4463   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4464   if (off) {
4465     PetscInt numCorners = 0;
4466 
4467     numEdges = off[numCells]/2;
4468 #if 0
4469     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
4470     numEdges += 3*numCells - off[numCells];
4471 #else
4472     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
4473     for (c = cStart; c < cEnd; ++c) {
4474       PetscInt coneSize;
4475 
4476       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
4477       numCorners += coneSize;
4478     }
4479     numEdges += numCorners - off[numCells];
4480 #endif
4481   }
4482 #if 0
4483   /* Check Euler characteristic V - E + F = 1 */
4484   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
4485 #endif
4486   /* Create interpolated mesh */
4487   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4488   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4489   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4490   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
4491   for (c = 0; c < numCells; ++c) {
4492     PetscInt numCorners;
4493 
4494     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
4495     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4496   }
4497   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4498     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4499   }
4500   ierr = DMSetUp(idm);CHKERRQ(ierr);
4501   /* Get edge cones from subsets of cell vertices */
4502   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
4503   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
4504 
4505   for (c = 0, edge = firstEdge; c < numCells; ++c) {
4506     const PetscInt *cellFaces;
4507     PetscInt        numCellFaces, faceSize, cf;
4508 
4509     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4510     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4511     for (cf = 0; cf < numCellFaces; ++cf) {
4512 #if 1
4513       PetscHashIJKey key;
4514 
4515       key.i = PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4516       key.j = PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]);
4517       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
4518       if (e < 0) {
4519         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4520         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
4521         e    = edge++;
4522       }
4523 #else
4524       PetscBool found = PETSC_FALSE;
4525 
4526       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4527       for (e = firstEdge; e < edge; ++e) {
4528         const PetscInt *cone;
4529 
4530         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4531         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4532             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4533           found = PETSC_TRUE;
4534           break;
4535         }
4536       }
4537       if (!found) {
4538         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4539         ++edge;
4540       }
4541 #endif
4542       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
4543     }
4544   }
4545   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4546   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4547   ierr = PetscFree(off);CHKERRQ(ierr);
4548   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4549   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4550   mesh = (DM_Plex *) (idm)->data;
4551   /* Orient edges */
4552   for (c = 0; c < numCells; ++c) {
4553     const PetscInt *cone = PETSC_NULL, *cellFaces;
4554     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4555 
4556     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4557     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4558     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4559     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4560     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4561     for (cf = 0; cf < numCellFaces; ++cf) {
4562       const PetscInt *econe = PETSC_NULL;
4563       PetscInt        esize;
4564 
4565       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4566       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4567       if (esize != 2) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4568       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4569         /* Correctly oriented */
4570         mesh->coneOrientations[coff+cf] = 0;
4571       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4572         /* Start at index 1, and reverse orientation */
4573         mesh->coneOrientations[coff+cf] = -(1+1);
4574       }
4575     }
4576   }
4577   *dmInt  = idm;
4578   PetscFunctionReturn(0);
4579 }
4580 
4581 #undef __FUNCT__
4582 #define __FUNCT__ "DMPlexInterpolate_3D"
4583 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4584 {
4585   DM             idm, fdm;
4586   DM_Plex    *mesh;
4587   PetscInt      *off;
4588   const PetscInt numCorners = 4;
4589   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4590   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4591   PetscErrorCode ierr;
4592 
4593   PetscFunctionBegin;
4594   {
4595     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4596     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4597     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4598   }
4599   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4600   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4601   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4602   numCells    = cEnd - cStart;
4603   numVertices = vEnd - vStart;
4604   firstFace   = numCells + numVertices;
4605   numFaces    = 0 ;
4606   /* Count faces using algorithm from CreateNeighborCSR */
4607   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4608   if (off) {
4609     numFaces = off[numCells]/2;
4610     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4611     numFaces += 4*numCells - off[numCells];
4612   }
4613   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4614   firstEdge = firstFace + numFaces;
4615   numEdges  = numVertices + numFaces - numCells - 1;
4616   /* Create interpolated mesh */
4617   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4618   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4619   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4620   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4621   for (c = 0; c < numCells; ++c) {
4622     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4623   }
4624   for (f = firstFace; f < firstFace+numFaces; ++f) {
4625     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4626   }
4627   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4628     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4629   }
4630   ierr = DMSetUp(idm);CHKERRQ(ierr);
4631   /* Get face cones from subsets of cell vertices */
4632   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4633   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4634   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4635   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4636   for (f = firstFace; f < firstFace+numFaces; ++f) {
4637     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4638   }
4639   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4640   for (c = 0, face = firstFace; c < numCells; ++c) {
4641     const PetscInt *cellFaces;
4642     PetscInt        numCellFaces, faceSize, cf;
4643 
4644     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4645     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4646     for (cf = 0; cf < numCellFaces; ++cf) {
4647       PetscBool found = PETSC_FALSE;
4648 
4649       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4650       for (f = firstFace; f < face; ++f) {
4651         const PetscInt *cone = PETSC_NULL;
4652 
4653         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4654         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4655             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4656             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4657             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4658             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4659             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4660           found = PETSC_TRUE;
4661           break;
4662         }
4663       }
4664       if (!found) {
4665         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4666         /* Save the vertices for orientation calculation */
4667         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4668         ++face;
4669       }
4670       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4671     }
4672   }
4673   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4674   /* Get edge cones from subsets of face vertices */
4675   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4676     const PetscInt *cellFaces;
4677     PetscInt        numCellFaces, faceSize, cf;
4678 
4679     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4680     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4681     for (cf = 0; cf < numCellFaces; ++cf) {
4682       PetscBool found = PETSC_FALSE;
4683 
4684       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4685       for (e = firstEdge; e < edge; ++e) {
4686         const PetscInt *cone = PETSC_NULL;
4687 
4688         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4689         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4690             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4691           found = PETSC_TRUE;
4692           break;
4693         }
4694       }
4695       if (!found) {
4696         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4697         ++edge;
4698       }
4699       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4700     }
4701   }
4702   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4703   ierr = PetscFree(off);CHKERRQ(ierr);
4704   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4705   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4706   mesh = (DM_Plex *) (idm)->data;
4707   /* Orient edges */
4708   for (f = firstFace; f < firstFace+numFaces; ++f) {
4709     const PetscInt *cone, *cellFaces;
4710     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4711 
4712     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4713     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4714     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4715     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4716     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4717     for (cf = 0; cf < numCellFaces; ++cf) {
4718       const PetscInt *econe;
4719       PetscInt        esize;
4720 
4721       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4722       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4723       if (esize != 2) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edge endpoints %D for edge %D should be 2", esize, cone[cf]);
4724       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4725         /* Correctly oriented */
4726         mesh->coneOrientations[coff+cf] = 0;
4727       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4728         /* Start at index 1, and reverse orientation */
4729         mesh->coneOrientations[coff+cf] = -(1+1);
4730       }
4731     }
4732   }
4733   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4734   /* Orient faces */
4735   for (c = 0; c < numCells; ++c) {
4736     const PetscInt *cone, *cellFaces;
4737     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4738 
4739     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4740     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4741     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4742     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4743     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4744     for (cf = 0; cf < numCellFaces; ++cf) {
4745       PetscInt *origClosure = PETSC_NULL, *closure;
4746       PetscInt  closureSize, i;
4747 
4748       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4749       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4750       for (i = 4; i < 7; ++i) {
4751         if ((origClosure[i*2] < vStart) || (origClosure[i*2] >= vEnd)) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure point %D should be a vertex in [%D, %D)", origClosure[i*2], vStart, vEnd);
4752       }
4753       closure = &origClosure[4*2];
4754       /* Remember that this is the orientation for edges, not vertices */
4755       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4756         /* Correctly oriented */
4757         mesh->coneOrientations[coff+cf] = 0;
4758       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4759         /* Shifted by 1 */
4760         mesh->coneOrientations[coff+cf] = 1;
4761       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4762         /* Shifted by 2 */
4763         mesh->coneOrientations[coff+cf] = 2;
4764       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4765         /* Start at edge 1, and reverse orientation */
4766         mesh->coneOrientations[coff+cf] = -(1+1);
4767       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4768         /* Start at index 0, and reverse orientation */
4769         mesh->coneOrientations[coff+cf] = -(0+1);
4770       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4771         /* Start at index 2, and reverse orientation */
4772         mesh->coneOrientations[coff+cf] = -(2+1);
4773       } else SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Face %D did not match local face %D in cell %D for any orientation", cone[cf], cf, c);
4774       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4775     }
4776   }
4777   {
4778     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4779     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4780     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4781   }
4782   *dmInt  = idm;
4783   PetscFunctionReturn(0);
4784 }
4785 
4786 #undef __FUNCT__
4787 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4788 /*
4789   This takes as input the common mesh generator output, a list of the vertices for each cell
4790 */
4791 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4792 {
4793   PetscInt      *cone, c, p;
4794   PetscErrorCode ierr;
4795 
4796   PetscFunctionBegin;
4797   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4798   for (c = 0; c < numCells; ++c) {
4799     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4800   }
4801   ierr = DMSetUp(dm);CHKERRQ(ierr);
4802   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4803   for (c = 0; c < numCells; ++c) {
4804     for (p = 0; p < numCorners; ++p) {
4805       cone[p] = cells[c*numCorners+p]+numCells;
4806     }
4807     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4808   }
4809   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4810   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4811   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4812   PetscFunctionReturn(0);
4813 }
4814 
4815 #undef __FUNCT__
4816 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4817 /*
4818   This takes as input the coordinates for each vertex
4819 */
4820 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4821 {
4822   PetscSection   coordSection;
4823   Vec            coordinates;
4824   PetscScalar   *coords;
4825   PetscInt       coordSize, v, d;
4826   PetscErrorCode ierr;
4827 
4828   PetscFunctionBegin;
4829   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4830   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4831   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4832   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4833   for (v = numCells; v < numCells+numVertices; ++v) {
4834     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4835     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4836   }
4837   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4838   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4839   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4840   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4841   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4842   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4843   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4844   for (v = 0; v < numVertices; ++v) {
4845     for (d = 0; d < spaceDim; ++d) {
4846       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4847     }
4848   }
4849   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4850   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4851   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4852   PetscFunctionReturn(0);
4853 }
4854 
4855 #undef __FUNCT__
4856 #define __FUNCT__ "DMPlexCreateFromCellList"
4857 /*
4858   This takes as input the common mesh generator output, a list of the vertices for each cell
4859 */
4860 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4861 {
4862   PetscErrorCode ierr;
4863 
4864   PetscFunctionBegin;
4865   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4866   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4867   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4868   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4869   if (interpolate) {
4870     DM idm;
4871 
4872     switch (dim) {
4873     case 2:
4874       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4875     case 3:
4876       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4877     default:
4878       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4879     }
4880     ierr = DMDestroy(dm);CHKERRQ(ierr);
4881     *dm  = idm;
4882   }
4883   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4884   PetscFunctionReturn(0);
4885 }
4886 
4887 #if defined(PETSC_HAVE_TRIANGLE)
4888 #include <triangle.h>
4889 
4890 #undef __FUNCT__
4891 #define __FUNCT__ "InitInput_Triangle"
4892 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx)
4893 {
4894   PetscFunctionBegin;
4895   inputCtx->numberofpoints = 0;
4896   inputCtx->numberofpointattributes = 0;
4897   inputCtx->pointlist = PETSC_NULL;
4898   inputCtx->pointattributelist = PETSC_NULL;
4899   inputCtx->pointmarkerlist = PETSC_NULL;
4900   inputCtx->numberofsegments = 0;
4901   inputCtx->segmentlist = PETSC_NULL;
4902   inputCtx->segmentmarkerlist = PETSC_NULL;
4903   inputCtx->numberoftriangleattributes = 0;
4904   inputCtx->trianglelist = PETSC_NULL;
4905   inputCtx->numberofholes = 0;
4906   inputCtx->holelist = PETSC_NULL;
4907   inputCtx->numberofregions = 0;
4908   inputCtx->regionlist = PETSC_NULL;
4909   PetscFunctionReturn(0);
4910 }
4911 
4912 #undef __FUNCT__
4913 #define __FUNCT__ "InitOutput_Triangle"
4914 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx)
4915 {
4916   PetscFunctionBegin;
4917   outputCtx->numberofpoints = 0;
4918   outputCtx->pointlist = PETSC_NULL;
4919   outputCtx->pointattributelist = PETSC_NULL;
4920   outputCtx->pointmarkerlist = PETSC_NULL;
4921   outputCtx->numberoftriangles = 0;
4922   outputCtx->trianglelist = PETSC_NULL;
4923   outputCtx->triangleattributelist = PETSC_NULL;
4924   outputCtx->neighborlist = PETSC_NULL;
4925   outputCtx->segmentlist = PETSC_NULL;
4926   outputCtx->segmentmarkerlist = PETSC_NULL;
4927   outputCtx->numberofedges = 0;
4928   outputCtx->edgelist = PETSC_NULL;
4929   outputCtx->edgemarkerlist = PETSC_NULL;
4930   PetscFunctionReturn(0);
4931 }
4932 
4933 #undef __FUNCT__
4934 #define __FUNCT__ "FiniOutput_Triangle"
4935 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx)
4936 {
4937   PetscFunctionBegin;
4938   free(outputCtx->pointmarkerlist);
4939   free(outputCtx->edgelist);
4940   free(outputCtx->edgemarkerlist);
4941   free(outputCtx->trianglelist);
4942   free(outputCtx->neighborlist);
4943   PetscFunctionReturn(0);
4944 }
4945 
4946 #undef __FUNCT__
4947 #define __FUNCT__ "DMPlexGenerate_Triangle"
4948 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4949 {
4950   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4951   PetscInt             dim              = 2;
4952   const PetscBool      createConvexHull = PETSC_FALSE;
4953   const PetscBool      constrained      = PETSC_FALSE;
4954   struct triangulateio in;
4955   struct triangulateio out;
4956   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4957   PetscMPIInt          rank;
4958   PetscErrorCode       ierr;
4959 
4960   PetscFunctionBegin;
4961   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4962   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4963   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4964   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4965   in.numberofpoints = vEnd - vStart;
4966   if (in.numberofpoints > 0) {
4967     PetscSection coordSection;
4968     Vec          coordinates;
4969     PetscScalar *array;
4970 
4971     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4972     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4973     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4974     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4975     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4976     for (v = vStart; v < vEnd; ++v) {
4977       const PetscInt idx = v - vStart;
4978       PetscInt       off, d;
4979 
4980       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4981       for (d = 0; d < dim; ++d) {
4982         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4983       }
4984       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4985     }
4986     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4987   }
4988   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4989   in.numberofsegments = eEnd - eStart;
4990   if (in.numberofsegments > 0) {
4991     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4992     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4993     for (e = eStart; e < eEnd; ++e) {
4994       const PetscInt  idx = e - eStart;
4995       const PetscInt *cone;
4996 
4997       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4998       in.segmentlist[idx*2+0] = cone[0] - vStart;
4999       in.segmentlist[idx*2+1] = cone[1] - vStart;
5000       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
5001     }
5002   }
5003 #if 0 /* Do not currently support holes */
5004   PetscReal *holeCoords;
5005   PetscInt   h, d;
5006 
5007   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5008   if (in.numberofholes > 0) {
5009     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5010     for (h = 0; h < in.numberofholes; ++h) {
5011       for (d = 0; d < dim; ++d) {
5012         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5013       }
5014     }
5015   }
5016 #endif
5017   if (!rank) {
5018     char args[32];
5019 
5020     /* Take away 'Q' for verbose output */
5021     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5022     if (createConvexHull) {
5023       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
5024     }
5025     if (constrained) {
5026       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
5027     }
5028     triangulate(args, &in, &out, PETSC_NULL);
5029   }
5030   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5031   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5032   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5033   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5034   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
5035 
5036   {
5037     const PetscInt numCorners  = 3;
5038     const PetscInt numCells    = out.numberoftriangles;
5039     const PetscInt numVertices = out.numberofpoints;
5040     const int     *cells       = out.trianglelist;
5041     const double  *meshCoords  = out.pointlist;
5042 
5043     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5044     /* Set labels */
5045     for (v = 0; v < numVertices; ++v) {
5046       if (out.pointmarkerlist[v]) {
5047         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5048       }
5049     }
5050     if (interpolate) {
5051       for (e = 0; e < out.numberofedges; e++) {
5052         if (out.edgemarkerlist[e]) {
5053           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5054           const PetscInt *edges;
5055           PetscInt        numEdges;
5056 
5057           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5058           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5059           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5060           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5061         }
5062       }
5063     }
5064     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5065   }
5066 #if 0 /* Do not currently support holes */
5067   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5068 #endif
5069   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5070   PetscFunctionReturn(0);
5071 }
5072 
5073 #undef __FUNCT__
5074 #define __FUNCT__ "DMPlexRefine_Triangle"
5075 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
5076 {
5077   MPI_Comm             comm = ((PetscObject) dm)->comm;
5078   PetscInt             dim  = 2;
5079   struct triangulateio in;
5080   struct triangulateio out;
5081   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5082   PetscMPIInt          rank;
5083   PetscErrorCode       ierr;
5084 
5085   PetscFunctionBegin;
5086   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5087   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
5088   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
5089   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5090   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5091   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5092   in.numberofpoints = vEnd - vStart;
5093   if (in.numberofpoints > 0) {
5094     PetscSection coordSection;
5095     Vec          coordinates;
5096     PetscScalar *array;
5097 
5098     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
5099     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
5100     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5101     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5102     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5103     for (v = vStart; v < vEnd; ++v) {
5104       const PetscInt idx = v - vStart;
5105       PetscInt       off, d;
5106 
5107       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5108       for (d = 0; d < dim; ++d) {
5109         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5110       }
5111       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5112     }
5113     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5114   }
5115   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5116   in.numberofcorners   = 3;
5117   in.numberoftriangles = cEnd - cStart;
5118   in.trianglearealist  = (double *) maxVolumes;
5119   if (in.numberoftriangles > 0) {
5120     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
5121     for (c = cStart; c < cEnd; ++c) {
5122       const PetscInt idx     = c - cStart;
5123       PetscInt      *closure = PETSC_NULL;
5124       PetscInt       closureSize;
5125 
5126       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5127       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
5128       for (v = 0; v < 3; ++v) {
5129         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
5130       }
5131       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5132     }
5133   }
5134   /* TODO: Segment markers are missing on input */
5135 #if 0 /* Do not currently support holes */
5136   PetscReal *holeCoords;
5137   PetscInt   h, d;
5138 
5139   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
5140   if (in.numberofholes > 0) {
5141     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
5142     for (h = 0; h < in.numberofholes; ++h) {
5143       for (d = 0; d < dim; ++d) {
5144         in.holelist[h*dim+d] = holeCoords[h*dim+d];
5145       }
5146     }
5147   }
5148 #endif
5149   if (!rank) {
5150     char args[32];
5151 
5152     /* Take away 'Q' for verbose output */
5153     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
5154     triangulate(args, &in, &out, PETSC_NULL);
5155   }
5156   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
5157   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
5158   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
5159   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
5160   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
5161 
5162   {
5163     const PetscInt numCorners  = 3;
5164     const PetscInt numCells    = out.numberoftriangles;
5165     const PetscInt numVertices = out.numberofpoints;
5166     const int     *cells       = out.trianglelist;
5167     const double  *meshCoords  = out.pointlist;
5168     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5169 
5170     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5171     /* Set labels */
5172     for (v = 0; v < numVertices; ++v) {
5173       if (out.pointmarkerlist[v]) {
5174         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5175       }
5176     }
5177     if (interpolate) {
5178       PetscInt e;
5179 
5180       for (e = 0; e < out.numberofedges; e++) {
5181         if (out.edgemarkerlist[e]) {
5182           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5183           const PetscInt *edges;
5184           PetscInt        numEdges;
5185 
5186           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5187           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5188           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5189           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5190         }
5191       }
5192     }
5193     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5194   }
5195 #if 0 /* Do not currently support holes */
5196   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
5197 #endif
5198   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
5199   PetscFunctionReturn(0);
5200 }
5201 #endif
5202 
5203 #if defined(PETSC_HAVE_TETGEN)
5204 #include <tetgen.h>
5205 #undef __FUNCT__
5206 #define __FUNCT__ "DMPlexGenerate_Tetgen"
5207 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
5208 {
5209   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5210   const PetscInt dim  = 3;
5211   ::tetgenio     in;
5212   ::tetgenio     out;
5213   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
5214   PetscMPIInt    rank;
5215   PetscErrorCode ierr;
5216 
5217   PetscFunctionBegin;
5218   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5219   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5220   in.numberofpoints = vEnd - vStart;
5221   if (in.numberofpoints > 0) {
5222     PetscSection coordSection;
5223     Vec          coordinates;
5224     PetscScalar *array;
5225 
5226     in.pointlist       = new double[in.numberofpoints*dim];
5227     in.pointmarkerlist = new int[in.numberofpoints];
5228     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5229     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5230     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5231     for (v = vStart; v < vEnd; ++v) {
5232       const PetscInt idx = v - vStart;
5233       PetscInt       off, d;
5234 
5235       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5236       for (d = 0; d < dim; ++d) {
5237         in.pointlist[idx*dim + d] = array[off+d];
5238       }
5239       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5240     }
5241     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5242   }
5243   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5244   in.numberoffacets = fEnd - fStart;
5245   if (in.numberoffacets > 0) {
5246     in.facetlist       = new tetgenio::facet[in.numberoffacets];
5247     in.facetmarkerlist = new int[in.numberoffacets];
5248     for (f = fStart; f < fEnd; ++f) {
5249       const PetscInt idx    = f - fStart;
5250       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
5251 
5252       in.facetlist[idx].numberofpolygons = 1;
5253       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
5254       in.facetlist[idx].numberofholes    = 0;
5255       in.facetlist[idx].holelist         = NULL;
5256 
5257       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5258       for (p = 0; p < numPoints*2; p += 2) {
5259         const PetscInt point = points[p];
5260         if ((point >= vStart) && (point < vEnd)) {
5261           points[numVertices++] = point;
5262         }
5263       }
5264 
5265       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
5266       poly->numberofvertices = numVertices;
5267       poly->vertexlist       = new int[poly->numberofvertices];
5268       for (v = 0; v < numVertices; ++v) {
5269         const PetscInt vIdx = points[v] - vStart;
5270         poly->vertexlist[v] = vIdx;
5271       }
5272       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
5273       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5274     }
5275   }
5276   if (!rank) {
5277     char args[32];
5278 
5279     /* Take away 'Q' for verbose output */
5280     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
5281     ::tetrahedralize(args, &in, &out);
5282   }
5283   {
5284     const PetscInt numCorners  = 4;
5285     const PetscInt numCells    = out.numberoftetrahedra;
5286     const PetscInt numVertices = out.numberofpoints;
5287     const int     *cells       = out.tetrahedronlist;
5288     const double  *meshCoords  = out.pointlist;
5289 
5290     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5291     /* Set labels */
5292     for (v = 0; v < numVertices; ++v) {
5293       if (out.pointmarkerlist[v]) {
5294         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5295       }
5296     }
5297     if (interpolate) {
5298       PetscInt e;
5299 
5300       for (e = 0; e < out.numberofedges; e++) {
5301         if (out.edgemarkerlist[e]) {
5302           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5303           const PetscInt *edges;
5304           PetscInt        numEdges;
5305 
5306           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5307           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5308           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5309           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5310         }
5311       }
5312       for (f = 0; f < out.numberoftrifaces; f++) {
5313         if (out.trifacemarkerlist[f]) {
5314           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5315           const PetscInt *faces;
5316           PetscInt        numFaces;
5317 
5318           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5319           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5320           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5321           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5322         }
5323       }
5324     }
5325     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5326   }
5327   PetscFunctionReturn(0);
5328 }
5329 
5330 #undef __FUNCT__
5331 #define __FUNCT__ "DMPlexRefine_Tetgen"
5332 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
5333 {
5334   MPI_Comm       comm = ((PetscObject) dm)->comm;
5335   const PetscInt dim  = 3;
5336   ::tetgenio     in;
5337   ::tetgenio     out;
5338   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5339   PetscMPIInt    rank;
5340   PetscErrorCode ierr;
5341 
5342   PetscFunctionBegin;
5343   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5344   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5345   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5346   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5347   in.numberofpoints = vEnd - vStart;
5348   if (in.numberofpoints > 0) {
5349     PetscSection coordSection;
5350     Vec          coordinates;
5351     PetscScalar *array;
5352 
5353     in.pointlist       = new double[in.numberofpoints*dim];
5354     in.pointmarkerlist = new int[in.numberofpoints];
5355     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5356     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5357     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5358     for (v = vStart; v < vEnd; ++v) {
5359       const PetscInt idx = v - vStart;
5360       PetscInt       off, d;
5361 
5362       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5363       for (d = 0; d < dim; ++d) {
5364         in.pointlist[idx*dim + d] = array[off+d];
5365       }
5366       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
5367     }
5368     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5369   }
5370   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5371   in.numberofcorners       = 4;
5372   in.numberoftetrahedra    = cEnd - cStart;
5373   in.tetrahedronvolumelist = (double *) maxVolumes;
5374   if (in.numberoftetrahedra > 0) {
5375     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
5376     for (c = cStart; c < cEnd; ++c) {
5377       const PetscInt idx     = c - cStart;
5378       PetscInt      *closure = PETSC_NULL;
5379       PetscInt       closureSize;
5380 
5381       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5382       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5383       for (v = 0; v < 4; ++v) {
5384         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5385       }
5386       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5387     }
5388   }
5389   /* TODO: Put in boundary faces with markers */
5390   if (!rank) {
5391     char args[32];
5392 
5393     /* Take away 'Q' for verbose output */
5394     /*ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr); */
5395     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
5396     ::tetrahedralize(args, &in, &out);
5397   }
5398   in.tetrahedronvolumelist = NULL;
5399 
5400   {
5401     const PetscInt numCorners  = 4;
5402     const PetscInt numCells    = out.numberoftetrahedra;
5403     const PetscInt numVertices = out.numberofpoints;
5404     const int     *cells       = out.tetrahedronlist;
5405     const double  *meshCoords  = out.pointlist;
5406     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5407 
5408     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5409     /* Set labels */
5410     for (v = 0; v < numVertices; ++v) {
5411       if (out.pointmarkerlist[v]) {
5412         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
5413       }
5414     }
5415     if (interpolate) {
5416       PetscInt e, f;
5417 
5418       for (e = 0; e < out.numberofedges; e++) {
5419         if (out.edgemarkerlist[e]) {
5420           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
5421           const PetscInt *edges;
5422           PetscInt        numEdges;
5423 
5424           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5425           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5426           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
5427           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5428         }
5429       }
5430       for (f = 0; f < out.numberoftrifaces; f++) {
5431         if (out.trifacemarkerlist[f]) {
5432           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
5433           const PetscInt *faces;
5434           PetscInt        numFaces;
5435 
5436           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5437           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5438           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
5439           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5440         }
5441       }
5442     }
5443     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5444   }
5445   PetscFunctionReturn(0);
5446 }
5447 #endif
5448 
5449 #if defined(PETSC_HAVE_CTETGEN)
5450 #include "ctetgen.h"
5451 
5452 #undef __FUNCT__
5453 #define __FUNCT__ "DMPlexGenerate_CTetgen"
5454 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
5455 {
5456   MPI_Comm       comm = ((PetscObject) boundary)->comm;
5457   const PetscInt dim  = 3;
5458   PLC           *in, *out;
5459   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
5460   PetscMPIInt    rank;
5461   PetscErrorCode ierr;
5462 
5463   PetscFunctionBegin;
5464   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5465   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5466   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
5467   ierr = PLCCreate(&in);CHKERRQ(ierr);
5468   ierr = PLCCreate(&out);CHKERRQ(ierr);
5469   in->numberofpoints = vEnd - vStart;
5470   if (in->numberofpoints > 0) {
5471     PetscSection coordSection;
5472     Vec          coordinates;
5473     PetscScalar *array;
5474 
5475     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5476     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5477     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
5478     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
5479     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5480     for (v = vStart; v < vEnd; ++v) {
5481       const PetscInt idx = v - vStart;
5482       PetscInt       off, d, m;
5483 
5484       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5485       for (d = 0; d < dim; ++d) {
5486         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5487       }
5488       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
5489       in->pointmarkerlist[idx] = (int) m;
5490     }
5491     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5492   }
5493   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
5494   in->numberoffacets = fEnd - fStart;
5495   if (in->numberoffacets > 0) {
5496     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
5497     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
5498     for (f = fStart; f < fEnd; ++f) {
5499       const PetscInt idx    = f - fStart;
5500       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
5501       polygon       *poly;
5502 
5503       in->facetlist[idx].numberofpolygons = 1;
5504       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
5505       in->facetlist[idx].numberofholes    = 0;
5506       in->facetlist[idx].holelist         = PETSC_NULL;
5507 
5508       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5509       for (p = 0; p < numPoints*2; p += 2) {
5510         const PetscInt point = points[p];
5511         if ((point >= vStart) && (point < vEnd)) {
5512           points[numVertices++] = point;
5513         }
5514       }
5515 
5516       poly = in->facetlist[idx].polygonlist;
5517       poly->numberofvertices = numVertices;
5518       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
5519       for (v = 0; v < numVertices; ++v) {
5520         const PetscInt vIdx = points[v] - vStart;
5521         poly->vertexlist[v] = vIdx;
5522       }
5523       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
5524       in->facetmarkerlist[idx] = (int) m;
5525       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
5526     }
5527   }
5528   if (!rank) {
5529     TetGenOpts t;
5530 
5531     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5532     t.in        = boundary; /* Should go away */
5533     t.plc       = 1;
5534     t.quality   = 1;
5535     t.edgesout  = 1;
5536     t.zeroindex = 1;
5537     t.quiet     = 1;
5538     t.verbose   = verbose;
5539     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5540     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5541   }
5542   {
5543     const PetscInt numCorners  = 4;
5544     const PetscInt numCells    = out->numberoftetrahedra;
5545     const PetscInt numVertices = out->numberofpoints;
5546     const int     *cells       = out->tetrahedronlist;
5547     const double  *meshCoords  = out->pointlist;
5548 
5549     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5550     /* Set labels */
5551     for (v = 0; v < numVertices; ++v) {
5552       if (out->pointmarkerlist[v]) {
5553         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5554       }
5555     }
5556     if (interpolate) {
5557       PetscInt e;
5558 
5559       for (e = 0; e < out->numberofedges; e++) {
5560         if (out->edgemarkerlist[e]) {
5561           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5562           const PetscInt *edges;
5563           PetscInt        numEdges;
5564 
5565           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5566           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5567           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5568           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5569         }
5570       }
5571       for (f = 0; f < out->numberoftrifaces; f++) {
5572         if (out->trifacemarkerlist[f]) {
5573           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5574           const PetscInt *faces;
5575           PetscInt        numFaces;
5576 
5577           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5578           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5579           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5580           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5581         }
5582       }
5583     }
5584     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5585   }
5586 
5587   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5588   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5589   PetscFunctionReturn(0);
5590 }
5591 
5592 #undef __FUNCT__
5593 #define __FUNCT__ "DMPlexRefine_CTetgen"
5594 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5595 {
5596   MPI_Comm       comm = ((PetscObject) dm)->comm;
5597   const PetscInt dim  = 3;
5598   PLC           *in, *out;
5599   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5600   PetscMPIInt    rank;
5601   PetscErrorCode ierr;
5602 
5603   PetscFunctionBegin;
5604   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5605   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5606   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5607   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5608   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5609   ierr = PLCCreate(&in);CHKERRQ(ierr);
5610   ierr = PLCCreate(&out);CHKERRQ(ierr);
5611   in->numberofpoints = vEnd - vStart;
5612   if (in->numberofpoints > 0) {
5613     PetscSection coordSection;
5614     Vec          coordinates;
5615     PetscScalar *array;
5616 
5617     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5618     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5619     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5620     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5621     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5622     for (v = vStart; v < vEnd; ++v) {
5623       const PetscInt idx = v - vStart;
5624       PetscInt       off, d, m;
5625 
5626       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5627       for (d = 0; d < dim; ++d) {
5628         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5629       }
5630       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5631       in->pointmarkerlist[idx] = (int) m;
5632     }
5633     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5634   }
5635   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5636   in->numberofcorners       = 4;
5637   in->numberoftetrahedra    = cEnd - cStart;
5638   in->tetrahedronvolumelist = maxVolumes;
5639   if (in->numberoftetrahedra > 0) {
5640     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5641     for (c = cStart; c < cEnd; ++c) {
5642       const PetscInt idx     = c - cStart;
5643       PetscInt      *closure = PETSC_NULL;
5644       PetscInt       closureSize;
5645 
5646       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5647       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5648       for (v = 0; v < 4; ++v) {
5649         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5650       }
5651       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5652     }
5653   }
5654   if (!rank) {
5655     TetGenOpts t;
5656 
5657     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5658     t.in        = dm; /* Should go away */
5659     t.refine    = 1;
5660     t.varvolume = 1;
5661     t.quality   = 1;
5662     t.edgesout  = 1;
5663     t.zeroindex = 1;
5664     t.quiet     = 1;
5665     t.verbose   = verbose; /* Change this */
5666     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5667     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5668   }
5669   {
5670     const PetscInt numCorners  = 4;
5671     const PetscInt numCells    = out->numberoftetrahedra;
5672     const PetscInt numVertices = out->numberofpoints;
5673     const int     *cells       = out->tetrahedronlist;
5674     const double  *meshCoords  = out->pointlist;
5675     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5676 
5677     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5678     /* Set labels */
5679     for (v = 0; v < numVertices; ++v) {
5680       if (out->pointmarkerlist[v]) {
5681         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5682       }
5683     }
5684     if (interpolate) {
5685       PetscInt e, f;
5686 
5687       for (e = 0; e < out->numberofedges; e++) {
5688         if (out->edgemarkerlist[e]) {
5689           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5690           const PetscInt *edges;
5691           PetscInt        numEdges;
5692 
5693           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5694           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5695           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5696           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5697         }
5698       }
5699       for (f = 0; f < out->numberoftrifaces; f++) {
5700         if (out->trifacemarkerlist[f]) {
5701           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5702           const PetscInt *faces;
5703           PetscInt        numFaces;
5704 
5705           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5706           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5707           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5708           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5709         }
5710       }
5711     }
5712     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5713   }
5714   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5715   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5716   PetscFunctionReturn(0);
5717 }
5718 #endif
5719 
5720 #undef __FUNCT__
5721 #define __FUNCT__ "DMPlexGenerate"
5722 /*@C
5723   DMPlexGenerate - Generates a mesh.
5724 
5725   Not Collective
5726 
5727   Input Parameters:
5728 + boundary - The DMPlex boundary object
5729 . name - The mesh generation package name
5730 - interpolate - Flag to create intermediate mesh elements
5731 
5732   Output Parameter:
5733 . mesh - The DMPlex object
5734 
5735   Level: intermediate
5736 
5737 .keywords: mesh, elements
5738 .seealso: DMPlexCreate(), DMRefine()
5739 @*/
5740 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5741 {
5742   PetscInt       dim;
5743   char           genname[1024];
5744   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5745   PetscErrorCode ierr;
5746 
5747   PetscFunctionBegin;
5748   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5749   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5750   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5751   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5752   if (flg) {name = genname;}
5753   if (name) {
5754     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5755     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5756     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5757   }
5758   switch (dim) {
5759   case 1:
5760     if (!name || isTriangle) {
5761 #if defined(PETSC_HAVE_TRIANGLE)
5762       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5763 #else
5764       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5765 #endif
5766     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5767     break;
5768   case 2:
5769     if (!name || isCTetgen) {
5770 #if defined(PETSC_HAVE_CTETGEN)
5771       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5772 #else
5773       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5774 #endif
5775     } else if (isTetgen) {
5776 #if defined(PETSC_HAVE_TETGEN)
5777       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5778 #else
5779       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5780 #endif
5781     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5782     break;
5783   default:
5784     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5785   }
5786   PetscFunctionReturn(0);
5787 }
5788 
5789 typedef PetscInt CellRefiner;
5790 
5791 #undef __FUNCT__
5792 #define __FUNCT__ "GetDepthStart_Private"
5793 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5794 {
5795   PetscFunctionBegin;
5796   if (cStart) *cStart = 0;
5797   if (vStart) *vStart = depthSize[depth];
5798   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5799   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5800   PetscFunctionReturn(0);
5801 }
5802 
5803 #undef __FUNCT__
5804 #define __FUNCT__ "GetDepthEnd_Private"
5805 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5806 {
5807   PetscFunctionBegin;
5808   if (cEnd) *cEnd = depthSize[depth];
5809   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5810   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5811   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5812   PetscFunctionReturn(0);
5813 }
5814 
5815 #undef __FUNCT__
5816 #define __FUNCT__ "CellRefinerGetSizes"
5817 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5818 {
5819   PetscInt       cStart, cEnd, cMax, vStart, vEnd, vMax, fStart, fEnd, fMax, eStart, eEnd, eMax;
5820   PetscErrorCode ierr;
5821 
5822   PetscFunctionBegin;
5823   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5824   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5825   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5826   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5827   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5828   switch (refiner) {
5829   case 1:
5830     /* Simplicial 2D */
5831     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5832     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5833     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5834     break;
5835   case 3:
5836     /* Hybrid 2D */
5837     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5838     cMax = PetscMin(cEnd, cMax);
5839     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5840     fMax = PetscMin(fEnd, fMax);
5841     depthSize[0] = vEnd - vStart + fMax - fStart;                                         /* Add a vertex on every face, but not hybrid faces */
5842     depthSize[1] = 2*(fMax - fStart) + 3*(cMax - cStart) + (fEnd - fMax) + (cEnd - cMax); /* Every interior face is split into 2 faces, 3 faces are added for each interior cell, and one in each hybrid cell */
5843     depthSize[2] = 4*(cMax - cStart) + 2*(cEnd - cMax);                                   /* Interior cells split into 4 cells, Hybrid cells split into 2 cells */
5844     break;
5845   case 2:
5846     /* Hex 2D */
5847     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5848     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5849     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5850     break;
5851   default:
5852     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5853   }
5854   PetscFunctionReturn(0);
5855 }
5856 
5857 #undef __FUNCT__
5858 #define __FUNCT__ "CellRefinerSetConeSizes"
5859 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5860 {
5861   PetscInt       depth, cStart, cStartNew, cEnd, cMax, c, vStart, vStartNew, vEnd, vMax, v, fStart, fStartNew, fEnd, fMax, f, eStart, eStartNew, eEnd, eMax, r;
5862   PetscErrorCode ierr;
5863 
5864   PetscFunctionBegin;
5865   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5866   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5867   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5868   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5869   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5870   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
5871   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5872   switch (refiner) {
5873   case 1:
5874     /* Simplicial 2D */
5875     /* All cells have 3 faces */
5876     for (c = cStart; c < cEnd; ++c) {
5877       for (r = 0; r < 4; ++r) {
5878         const PetscInt newp = (c - cStart)*4 + r;
5879 
5880         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5881       }
5882     }
5883     /* Split faces have 2 vertices and the same cells as the parent */
5884     for (f = fStart; f < fEnd; ++f) {
5885       for (r = 0; r < 2; ++r) {
5886         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5887         PetscInt       size;
5888 
5889         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5890         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5891         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5892       }
5893     }
5894     /* Interior faces have 2 vertices and 2 cells */
5895     for (c = cStart; c < cEnd; ++c) {
5896       for (r = 0; r < 3; ++r) {
5897         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5898 
5899         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5900         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5901       }
5902     }
5903     /* Old vertices have identical supports */
5904     for (v = vStart; v < vEnd; ++v) {
5905       const PetscInt newp = vStartNew + (v - vStart);
5906       PetscInt       size;
5907 
5908       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5909       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5910     }
5911     /* Face vertices have 2 + cells*2 supports */
5912     for (f = fStart; f < fEnd; ++f) {
5913       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5914       PetscInt       size;
5915 
5916       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5917       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5918     }
5919     break;
5920   case 2:
5921     /* Hex 2D */
5922     /* All cells have 4 faces */
5923     for (c = cStart; c < cEnd; ++c) {
5924       for (r = 0; r < 4; ++r) {
5925         const PetscInt newp = (c - cStart)*4 + r;
5926 
5927         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5928       }
5929     }
5930     /* Split faces have 2 vertices and the same cells as the parent */
5931     for (f = fStart; f < fEnd; ++f) {
5932       for (r = 0; r < 2; ++r) {
5933         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5934         PetscInt       size;
5935 
5936         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5937         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5938         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5939       }
5940     }
5941     /* Interior faces have 2 vertices and 2 cells */
5942     for (c = cStart; c < cEnd; ++c) {
5943       for (r = 0; r < 4; ++r) {
5944         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5945 
5946         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5947         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5948       }
5949     }
5950     /* Old vertices have identical supports */
5951     for (v = vStart; v < vEnd; ++v) {
5952       const PetscInt newp = vStartNew + (v - vStart);
5953       PetscInt       size;
5954 
5955       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5956       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5957     }
5958     /* Face vertices have 2 + cells supports */
5959     for (f = fStart; f < fEnd; ++f) {
5960       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5961       PetscInt       size;
5962 
5963       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5964       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5965     }
5966     /* Cell vertices have 4 supports */
5967     for (c = cStart; c < cEnd; ++c) {
5968       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5969 
5970       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5971     }
5972     break;
5973   case 3:
5974     /* Hybrid 2D */
5975     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
5976     cMax = PetscMin(cEnd, cMax);
5977     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
5978     fMax = PetscMin(fEnd, fMax);
5979     ierr = DMPlexSetHybridBounds(rdm, cStartNew + (cMax - cStart)*4, fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
5980     /* Interior cells have 3 faces */
5981     for (c = cStart; c < cMax; ++c) {
5982       for (r = 0; r < 4; ++r) {
5983         const PetscInt newp = cStartNew + (c - cStart)*4 + r;
5984 
5985         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5986       }
5987     }
5988     /* Hybrid cells have 4 faces */
5989     for (c = cMax; c < cEnd; ++c) {
5990       for (r = 0; r < 2; ++r) {
5991         const PetscInt newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2 + r;
5992 
5993         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5994       }
5995     }
5996     /* Interior split faces have 2 vertices and the same cells as the parent */
5997     for (f = fStart; f < fMax; ++f) {
5998       for (r = 0; r < 2; ++r) {
5999         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
6000         PetscInt       size;
6001 
6002         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6003         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6004         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6005       }
6006     }
6007     /* Interior cell faces have 2 vertices and 2 cells */
6008     for (c = cStart; c < cMax; ++c) {
6009       for (r = 0; r < 3; ++r) {
6010         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6011 
6012         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6013         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6014       }
6015     }
6016     /* Hybrid faces have 2 vertices and the same cells */
6017     for (f = fMax; f < fEnd; ++f) {
6018       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6019       PetscInt       size;
6020 
6021       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6022       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6023       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6024     }
6025     /* Hybrid cell faces have 2 vertices and 2 cells */
6026     for (c = cMax; c < cEnd; ++c) {
6027       const PetscInt newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6028 
6029       ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
6030       ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
6031     }
6032     /* Old vertices have identical supports */
6033     for (v = vStart; v < vEnd; ++v) {
6034       const PetscInt newp = vStartNew + (v - vStart);
6035       PetscInt       size;
6036 
6037       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6038       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
6039     }
6040     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6041     for (f = fStart; f < fMax; ++f) {
6042       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6043       const PetscInt *support;
6044       PetscInt        size, newSize = 2, s;
6045 
6046       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6047       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6048       for (s = 0; s < size; ++s) {
6049         if (support[s] >= cMax) {
6050           newSize += 1;
6051         } else {
6052           newSize += 2;
6053         }
6054       }
6055       ierr = DMPlexSetSupportSize(rdm, newp, newSize);CHKERRQ(ierr);
6056     }
6057     break;
6058   default:
6059     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6060   }
6061   PetscFunctionReturn(0);
6062 }
6063 
6064 #undef __FUNCT__
6065 #define __FUNCT__ "CellRefinerSetCones"
6066 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6067 {
6068   PetscInt       depth, cStart, cEnd, cMax, cStartNew, cEndNew, c, vStart, vEnd, vMax, vStartNew, vEndNew, v, fStart, fEnd, fMax, fStartNew, fEndNew, f, eStart, eEnd, eMax, eStartNew, eEndNew, r, p;
6069   PetscInt       maxSupportSize, *supportRef;
6070   PetscErrorCode ierr;
6071 
6072   PetscFunctionBegin;
6073   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6074   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6075   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6076   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6077   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6078   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
6079   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6080   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
6081   switch (refiner) {
6082   case 1:
6083     /* Simplicial 2D */
6084     /*
6085      2
6086      |\
6087      | \
6088      |  \
6089      |   \
6090      | C  \
6091      |     \
6092      |      \
6093      2---1---1
6094      |\  D  / \
6095      | 2   0   \
6096      |A \ /  B  \
6097      0---0-------1
6098      */
6099     /* All cells have 3 faces */
6100     for (c = cStart; c < cEnd; ++c) {
6101       const PetscInt  newp = cStartNew + (c - cStart)*4;
6102       const PetscInt *cone, *ornt;
6103       PetscInt        coneNew[3], orntNew[3];
6104 
6105       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6106       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6107       /* A triangle */
6108       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6109       orntNew[0] = ornt[0];
6110       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6111       orntNew[1] = -2;
6112       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6113       orntNew[2] = ornt[2];
6114       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6115       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6116 #if 1
6117       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6118       for (p = 0; p < 3; ++p) {
6119         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6120       }
6121 #endif
6122       /* B triangle */
6123       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6124       orntNew[0] = ornt[0];
6125       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6126       orntNew[1] = ornt[1];
6127       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6128       orntNew[2] = -2;
6129       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6130       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6131 #if 1
6132       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6133       for (p = 0; p < 3; ++p) {
6134         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6135       }
6136 #endif
6137       /* C triangle */
6138       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6139       orntNew[0] = -2;
6140       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6141       orntNew[1] = ornt[1];
6142       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6143       orntNew[2] = ornt[2];
6144       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6145       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6146 #if 1
6147       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6148       for (p = 0; p < 3; ++p) {
6149         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6150       }
6151 #endif
6152       /* D triangle */
6153       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
6154       orntNew[0] = 0;
6155       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
6156       orntNew[1] = 0;
6157       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
6158       orntNew[2] = 0;
6159       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6160       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6161 #if 1
6162       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6163       for (p = 0; p < 3; ++p) {
6164         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6165       }
6166 #endif
6167     }
6168     /* Split faces have 2 vertices and the same cells as the parent */
6169     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6170     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6171     for (f = fStart; f < fEnd; ++f) {
6172       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6173 
6174       for (r = 0; r < 2; ++r) {
6175         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6176         const PetscInt *cone, *support;
6177         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6178 
6179         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6180         coneNew[0] = vStartNew + (cone[0] - vStart);
6181         coneNew[1] = vStartNew + (cone[1] - vStart);
6182         coneNew[(r+1)%2] = newv;
6183         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6184 #if 1
6185         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6186         for (p = 0; p < 2; ++p) {
6187           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6188         }
6189 #endif
6190         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6191         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6192         for (s = 0; s < supportSize; ++s) {
6193           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6194           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6195           for (c = 0; c < coneSize; ++c) {
6196             if (cone[c] == f) {
6197               break;
6198             }
6199           }
6200           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6201         }
6202         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6203 #if 1
6204         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6205         for (p = 0; p < supportSize; ++p) {
6206           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6207         }
6208 #endif
6209       }
6210     }
6211     /* Interior faces have 2 vertices and 2 cells */
6212     for (c = cStart; c < cEnd; ++c) {
6213       const PetscInt *cone;
6214 
6215       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6216       for (r = 0; r < 3; ++r) {
6217         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
6218         PetscInt       coneNew[2];
6219         PetscInt       supportNew[2];
6220 
6221         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6222         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6223         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6224 #if 1
6225         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6226         for (p = 0; p < 2; ++p) {
6227           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6228         }
6229 #endif
6230         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6231         supportNew[1] = (c - cStart)*4 + 3;
6232         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6233 #if 1
6234         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6235         for (p = 0; p < 2; ++p) {
6236           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6237         }
6238 #endif
6239       }
6240     }
6241     /* Old vertices have identical supports */
6242     for (v = vStart; v < vEnd; ++v) {
6243       const PetscInt  newp = vStartNew + (v - vStart);
6244       const PetscInt *support, *cone;
6245       PetscInt        size, s;
6246 
6247       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6248       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6249       for (s = 0; s < size; ++s) {
6250         PetscInt r = 0;
6251 
6252         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6253         if (cone[1] == v) r = 1;
6254         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6255       }
6256       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6257 #if 1
6258       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6259       for (p = 0; p < size; ++p) {
6260         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6261       }
6262 #endif
6263     }
6264     /* Face vertices have 2 + cells*2 supports */
6265     for (f = fStart; f < fEnd; ++f) {
6266       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6267       const PetscInt *cone, *support;
6268       PetscInt        size, s;
6269 
6270       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6271       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6272       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6273       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6274       for (s = 0; s < size; ++s) {
6275         PetscInt r = 0;
6276 
6277         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6278         if      (cone[1] == f) r = 1;
6279         else if (cone[2] == f) r = 2;
6280         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6281         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
6282       }
6283       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6284 #if 1
6285       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6286       for (p = 0; p < 2+size*2; ++p) {
6287         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6288       }
6289 #endif
6290     }
6291     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6292     break;
6293   case 2:
6294     /* Hex 2D */
6295     /*
6296      3---------2---------2
6297      |         |         |
6298      |    D    2    C    |
6299      |         |         |
6300      3----3----0----1----1
6301      |         |         |
6302      |    A    0    B    |
6303      |         |         |
6304      0---------0---------1
6305      */
6306     /* All cells have 4 faces */
6307     for (c = cStart; c < cEnd; ++c) {
6308       const PetscInt  newp = (c - cStart)*4;
6309       const PetscInt *cone, *ornt;
6310       PetscInt        coneNew[4], orntNew[4];
6311 
6312       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6313       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6314       /* A quad */
6315       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6316       orntNew[0] = ornt[0];
6317       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6318       orntNew[1] = 0;
6319       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6320       orntNew[2] = -2;
6321       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
6322       orntNew[3] = ornt[3];
6323       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6324       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6325 #if 1
6326       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6327       for (p = 0; p < 4; ++p) {
6328         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6329       }
6330 #endif
6331       /* B quad */
6332       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6333       orntNew[0] = ornt[0];
6334       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6335       orntNew[1] = ornt[1];
6336       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6337       orntNew[2] = 0;
6338       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
6339       orntNew[3] = -2;
6340       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6341       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6342 #if 1
6343       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6344       for (p = 0; p < 4; ++p) {
6345         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6346       }
6347 #endif
6348       /* C quad */
6349       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
6350       orntNew[0] = -2;
6351       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6352       orntNew[1] = ornt[1];
6353       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6354       orntNew[2] = ornt[2];
6355       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6356       orntNew[3] = 0;
6357       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6358       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6359 #if 1
6360       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6361       for (p = 0; p < 4; ++p) {
6362         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6363       }
6364 #endif
6365       /* D quad */
6366       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
6367       orntNew[0] = 0;
6368       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
6369       orntNew[1] = -2;
6370       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6371       orntNew[2] = ornt[2];
6372       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
6373       orntNew[3] = ornt[3];
6374       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6375       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6376 #if 1
6377       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6378       for (p = 0; p < 4; ++p) {
6379         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6380       }
6381 #endif
6382     }
6383     /* Split faces have 2 vertices and the same cells as the parent */
6384     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6385     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6386     for (f = fStart; f < fEnd; ++f) {
6387       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6388 
6389       for (r = 0; r < 2; ++r) {
6390         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6391         const PetscInt *cone, *support;
6392         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6393 
6394         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6395         coneNew[0] = vStartNew + (cone[0] - vStart);
6396         coneNew[1] = vStartNew + (cone[1] - vStart);
6397         coneNew[(r+1)%2] = newv;
6398         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6399 #if 1
6400         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6401         for (p = 0; p < 2; ++p) {
6402           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6403         }
6404 #endif
6405         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6406         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6407         for (s = 0; s < supportSize; ++s) {
6408           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6409           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6410           for (c = 0; c < coneSize; ++c) {
6411             if (cone[c] == f) {
6412               break;
6413             }
6414           }
6415           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
6416         }
6417         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6418 #if 1
6419         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6420         for (p = 0; p < supportSize; ++p) {
6421           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6422         }
6423 #endif
6424       }
6425     }
6426     /* Interior faces have 2 vertices and 2 cells */
6427     for (c = cStart; c < cEnd; ++c) {
6428       const PetscInt *cone;
6429       PetscInt        coneNew[2], supportNew[2];
6430 
6431       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6432       for (r = 0; r < 4; ++r) {
6433         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6434 
6435         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
6436         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
6437         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6438 #if 1
6439         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6440         for (p = 0; p < 2; ++p) {
6441           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6442         }
6443 #endif
6444         supportNew[0] = (c - cStart)*4 + r;
6445         supportNew[1] = (c - cStart)*4 + (r+1)%4;
6446         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6447 #if 1
6448         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6449         for (p = 0; p < 2; ++p) {
6450           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6451         }
6452 #endif
6453       }
6454     }
6455     /* Old vertices have identical supports */
6456     for (v = vStart; v < vEnd; ++v) {
6457       const PetscInt  newp = vStartNew + (v - vStart);
6458       const PetscInt *support, *cone;
6459       PetscInt        size, s;
6460 
6461       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6462       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6463       for (s = 0; s < size; ++s) {
6464         PetscInt r = 0;
6465 
6466         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6467         if (cone[1] == v) r = 1;
6468         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6469       }
6470       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6471 #if 1
6472       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6473       for (p = 0; p < size; ++p) {
6474         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6475       }
6476 #endif
6477     }
6478     /* Face vertices have 2 + cells supports */
6479     for (f = fStart; f < fEnd; ++f) {
6480       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6481       const PetscInt *cone, *support;
6482       PetscInt        size, s;
6483 
6484       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6485       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6486       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6487       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6488       for (s = 0; s < size; ++s) {
6489         PetscInt r = 0;
6490 
6491         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6492         if      (cone[1] == f) r = 1;
6493         else if (cone[2] == f) r = 2;
6494         else if (cone[3] == f) r = 3;
6495         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
6496       }
6497       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6498 #if 1
6499       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6500       for (p = 0; p < 2+size; ++p) {
6501         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6502       }
6503 #endif
6504     }
6505     /* Cell vertices have 4 supports */
6506     for (c = cStart; c < cEnd; ++c) {
6507       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6508       PetscInt       supportNew[4];
6509 
6510       for (r = 0; r < 4; ++r) {
6511         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
6512       }
6513       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6514     }
6515     break;
6516   case 3:
6517     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
6518     cMax = PetscMin(cEnd, cMax);
6519     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
6520     fMax = PetscMin(fEnd, fMax);
6521     /* Interior cells have 3 faces */
6522     for (c = cStart; c < cMax; ++c) {
6523       const PetscInt  newp = cStartNew + (c - cStart)*4;
6524       const PetscInt *cone, *ornt;
6525       PetscInt        coneNew[3], orntNew[3];
6526 
6527       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6528       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6529       /* A triangle */
6530       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6531       orntNew[0] = ornt[0];
6532       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6533       orntNew[1] = -2;
6534       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
6535       orntNew[2] = ornt[2];
6536       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6537       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6538 #if 1
6539       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6540       for (p = 0; p < 3; ++p) {
6541         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6542       }
6543 #endif
6544       /* B triangle */
6545       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6546       orntNew[0] = ornt[0];
6547       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6548       orntNew[1] = ornt[1];
6549       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6550       orntNew[2] = -2;
6551       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6552       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6553 #if 1
6554       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6555       for (p = 0; p < 3; ++p) {
6556         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6557       }
6558 #endif
6559       /* C triangle */
6560       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6561       orntNew[0] = -2;
6562       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6563       orntNew[1] = ornt[1];
6564       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
6565       orntNew[2] = ornt[2];
6566       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
6567       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
6568 #if 1
6569       if ((newp+2 < cStartNew) || (newp+2 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+2, cStartNew, cEndNew);
6570       for (p = 0; p < 3; ++p) {
6571         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6572       }
6573 #endif
6574       /* D triangle */
6575       coneNew[0] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 0;
6576       orntNew[0] = 0;
6577       coneNew[1] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 1;
6578       orntNew[1] = 0;
6579       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (c - cStart)*3 + 2;
6580       orntNew[2] = 0;
6581       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
6582       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
6583 #if 1
6584       if ((newp+3 < cStartNew) || (newp+3 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+3, cStartNew, cEndNew);
6585       for (p = 0; p < 3; ++p) {
6586         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6587       }
6588 #endif
6589     }
6590     /*
6591      2----3----3
6592      |         |
6593      |    B    |
6594      |         |
6595      0----4--- 1
6596      |         |
6597      |    A    |
6598      |         |
6599      0----2----1
6600      */
6601     /* Hybrid cells have 4 faces */
6602     for (c = cMax; c < cEnd; ++c) {
6603       const PetscInt  newp = cStartNew + (cMax - cStart)*4 + (c - cMax)*2;
6604       const PetscInt *cone, *ornt;
6605       PetscInt        coneNew[4], orntNew[4];
6606 
6607       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6608       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
6609       /* A quad */
6610       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
6611       orntNew[0] = ornt[0];
6612       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
6613       orntNew[1] = ornt[1];
6614       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[2] - fMax);
6615       orntNew[2] = 0;
6616       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6617       orntNew[3] = 0;
6618       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
6619       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
6620 #if 1
6621       if ((newp+0 < cStartNew) || (newp+0 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+0, cStartNew, cEndNew);
6622       for (p = 0; p < 4; ++p) {
6623         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6624       }
6625 #endif
6626       /* B quad */
6627       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
6628       orntNew[0] = ornt[0];
6629       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
6630       orntNew[1] = ornt[1];
6631       coneNew[2] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (fEnd    - fMax) + (c - cMax);
6632       orntNew[2] = 0;
6633       coneNew[3] = fStartNew + (fMax    - fStart)*2 + (cMax - cStart)*3 + (cone[3] - fMax);
6634       orntNew[3] = 0;
6635       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
6636       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
6637 #if 1
6638       if ((newp+1 < cStartNew) || (newp+1 >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", newp+1, cStartNew, cEndNew);
6639       for (p = 0; p < 4; ++p) {
6640         if ((coneNew[p] < fStartNew) || (coneNew[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", coneNew[p], fStartNew, fEndNew);
6641       }
6642 #endif
6643     }
6644     /* Interior split faces have 2 vertices and the same cells as the parent */
6645     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
6646     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
6647     for (f = fStart; f < fMax; ++f) {
6648       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
6649 
6650       for (r = 0; r < 2; ++r) {
6651         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
6652         const PetscInt *cone, *support;
6653         PetscInt        coneNew[2], coneSize, c, supportSize, s;
6654 
6655         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6656         coneNew[0] = vStartNew + (cone[0] - vStart);
6657         coneNew[1] = vStartNew + (cone[1] - vStart);
6658         coneNew[(r+1)%2] = newv;
6659         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6660 #if 1
6661         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6662         for (p = 0; p < 2; ++p) {
6663           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6664         }
6665 #endif
6666         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
6667         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6668         for (s = 0; s < supportSize; ++s) {
6669           if (support[s] >= cMax) {
6670             supportRef[s] = cStartNew + (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6671           } else {
6672             ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
6673             ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6674             for (c = 0; c < coneSize; ++c) {
6675               if (cone[c] == f) {
6676                 break;
6677               }
6678             }
6679             supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
6680           }
6681         }
6682         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6683 #if 1
6684         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6685         for (p = 0; p < supportSize; ++p) {
6686           if ((supportRef[p] < cStartNew) || (supportRef[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportRef[p], cStartNew, cEndNew);
6687         }
6688 #endif
6689       }
6690     }
6691     /* Interior cell faces have 2 vertices and 2 cells */
6692     for (c = cStart; c < cMax; ++c) {
6693       const PetscInt *cone;
6694 
6695       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6696       for (r = 0; r < 3; ++r) {
6697         const PetscInt newp = fStartNew + (fMax - fStart)*2 + (c - cStart)*3 + r;
6698         PetscInt       coneNew[2];
6699         PetscInt       supportNew[2];
6700 
6701         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
6702         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
6703         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6704 #if 1
6705         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6706         for (p = 0; p < 2; ++p) {
6707           if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6708         }
6709 #endif
6710         supportNew[0] = (c - cStart)*4 + (r+1)%3;
6711         supportNew[1] = (c - cStart)*4 + 3;
6712         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6713 #if 1
6714         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6715         for (p = 0; p < 2; ++p) {
6716           if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6717         }
6718 #endif
6719       }
6720     }
6721     /* Interior hybrid faces have 2 vertices and the same cells */
6722     for (f = fMax; f < fEnd; ++f) {
6723       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (f - fMax);
6724       const PetscInt *cone;
6725       const PetscInt *support;
6726       PetscInt        coneNew[2];
6727       PetscInt        supportNew[2];
6728       PetscInt        size, s, r;
6729 
6730       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6731       coneNew[0] = vStartNew + (cone[0] - vStart);
6732       coneNew[1] = vStartNew + (cone[1] - vStart);
6733       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6734 #if 1
6735       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6736       for (p = 0; p < 2; ++p) {
6737         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6738       }
6739 #endif
6740       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6741       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6742       for (s = 0; s < size; ++s) {
6743         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6744         for (r = 0; r < 2; ++r) {
6745           if (cone[r+2] == f) break;
6746         }
6747         supportNew[s] = (cMax - cStart)*4 + (support[s] - cMax)*2 + r;
6748       }
6749       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6750 #if 1
6751       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6752       for (p = 0; p < size; ++p) {
6753         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6754       }
6755 #endif
6756     }
6757     /* Cell hybrid faces have 2 vertices and 2 cells */
6758     for (c = cMax; c < cEnd; ++c) {
6759       const PetscInt  newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (c - cMax);
6760       const PetscInt *cone;
6761       PetscInt        coneNew[2];
6762       PetscInt        supportNew[2];
6763 
6764       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
6765       coneNew[0] = vStartNew + (vEnd - vStart) + (cone[0] - fStart);
6766       coneNew[1] = vStartNew + (vEnd - vStart) + (cone[1] - fStart);
6767       ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
6768 #if 1
6769       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6770       for (p = 0; p < 2; ++p) {
6771         if ((coneNew[p] < vStartNew) || (coneNew[p] >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", coneNew[p], vStartNew, vEndNew);
6772       }
6773 #endif
6774       supportNew[0] = (cMax - cStart)*4 + (c - cMax)*2 + 0;
6775       supportNew[1] = (cMax - cStart)*4 + (c - cMax)*2 + 1;
6776       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
6777 #if 1
6778       if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
6779       for (p = 0; p < 2; ++p) {
6780         if ((supportNew[p] < cStartNew) || (supportNew[p] >= cEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a cell [%d, %d)", supportNew[p], cStartNew, cEndNew);
6781       }
6782 #endif
6783     }
6784     /* Old vertices have identical supports */
6785     for (v = vStart; v < vEnd; ++v) {
6786       const PetscInt  newp = vStartNew + (v - vStart);
6787       const PetscInt *support, *cone;
6788       PetscInt        size, s;
6789 
6790       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
6791       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
6792       for (s = 0; s < size; ++s) {
6793         if (support[s] >= fMax) {
6794           supportRef[s] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (support[s] - fMax);
6795         } else {
6796           PetscInt r = 0;
6797 
6798           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6799           if (cone[1] == v) r = 1;
6800           supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
6801         }
6802       }
6803       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6804 #if 1
6805       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6806       for (p = 0; p < size; ++p) {
6807         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6808       }
6809 #endif
6810     }
6811     /* Face vertices have 2 + (2 interior, 1 hybrid) supports */
6812     for (f = fStart; f < fMax; ++f) {
6813       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
6814       const PetscInt *cone, *support;
6815       PetscInt        size, newSize = 2, s;
6816 
6817       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
6818       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
6819       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
6820       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
6821       for (s = 0; s < size; ++s) {
6822         PetscInt r = 0;
6823 
6824         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
6825         if (support[s] >= cMax) {
6826           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (fEnd - fMax) + (support[s] - cMax);
6827           newSize += 1;
6828         } else {
6829           if      (cone[1] == f) r = 1;
6830           else if (cone[2] == f) r = 2;
6831           supportRef[newSize+0] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
6832           supportRef[newSize+1] = fStartNew + (fMax - fStart)*2 + (support[s] - cStart)*3 + r;
6833           newSize += 2;
6834         }
6835       }
6836       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
6837 #if 1
6838       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
6839       for (p = 0; p < newSize; ++p) {
6840         if ((supportRef[p] < fStartNew) || (supportRef[p] >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", supportRef[p], fStartNew, fEndNew);
6841       }
6842 #endif
6843     }
6844     ierr = PetscFree(supportRef);CHKERRQ(ierr);
6845     break;
6846   default:
6847     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6848   }
6849   PetscFunctionReturn(0);
6850 }
6851 
6852 #undef __FUNCT__
6853 #define __FUNCT__ "CellRefinerSetCoordinates"
6854 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6855 {
6856   PetscSection   coordSection, coordSectionNew;
6857   Vec            coordinates, coordinatesNew;
6858   PetscScalar   *coords, *coordsNew;
6859   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, fMax, f;
6860   PetscErrorCode ierr;
6861 
6862   PetscFunctionBegin;
6863   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6864   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6865   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6866   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6867   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6868   ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, &fMax, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
6869   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
6870   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
6871   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
6872   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
6873   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
6874   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
6875   if (fMax < 0) fMax = fEnd;
6876   switch (refiner) {
6877   case 1:
6878   case 2:
6879   case 3:
6880     /* Simplicial and Hex 2D */
6881     /* All vertices have the dim coordinates */
6882     for (v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
6883       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
6884       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
6885     }
6886     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
6887     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
6888     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
6889     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
6890     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
6891     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
6892     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
6893     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
6894     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
6895     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6896     /* Old vertices have the same coordinates */
6897     for (v = vStart; v < vEnd; ++v) {
6898       const PetscInt newv = vStartNew + (v - vStart);
6899       PetscInt       off, offnew, d;
6900 
6901       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
6902       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6903       for (d = 0; d < dim; ++d) {
6904         coordsNew[offnew+d] = coords[off+d];
6905       }
6906     }
6907     /* Face vertices have the average of endpoint coordinates */
6908     for (f = fStart; f < fMax; ++f) {
6909       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
6910       const PetscInt *cone;
6911       PetscInt        coneSize, offA, offB, offnew, d;
6912 
6913       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
6914       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
6915       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
6916       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6917       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6918       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6919       for (d = 0; d < dim; ++d) {
6920         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
6921       }
6922     }
6923     /* Just Hex 2D */
6924     if (refiner == 2) {
6925       /* Cell vertices have the average of corner coordinates */
6926       for (c = cStart; c < cEnd; ++c) {
6927         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
6928         PetscInt      *cone = PETSC_NULL;
6929         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
6930 
6931         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6932         for (p = 0; p < closureSize*2; p += 2) {
6933           const PetscInt point = cone[p];
6934           if ((point >= vStart) && (point < vEnd)) {
6935             cone[coneSize++] = point;
6936           }
6937         }
6938         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
6939         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
6940         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
6941         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
6942         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
6943         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
6944         for (d = 0; d < dim; ++d) {
6945           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
6946         }
6947         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
6948       }
6949     }
6950     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
6951     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
6952     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
6953     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
6954     break;
6955   default:
6956     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6957   }
6958   PetscFunctionReturn(0);
6959 }
6960 
6961 #undef __FUNCT__
6962 #define __FUNCT__ "DMPlexCreateProcessSF"
6963 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
6964 {
6965   PetscInt           numRoots, numLeaves, l;
6966   const PetscInt    *localPoints;
6967   const PetscSFNode *remotePoints;
6968   PetscInt          *localPointsNew;
6969   PetscSFNode       *remotePointsNew;
6970   PetscInt          *ranks, *ranksNew;
6971   PetscErrorCode     ierr;
6972 
6973   PetscFunctionBegin;
6974   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6975   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
6976   for (l = 0; l < numLeaves; ++l) {
6977     ranks[l] = remotePoints[l].rank;
6978   }
6979   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6980   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6981   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6982   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6983   for (l = 0; l < numLeaves; ++l) {
6984     ranksNew[l]              = ranks[l];
6985     localPointsNew[l]        = l;
6986     remotePointsNew[l].index = 0;
6987     remotePointsNew[l].rank  = ranksNew[l];
6988   }
6989   ierr = PetscFree(ranks);CHKERRQ(ierr);
6990   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6991   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6992   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6993   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6994   PetscFunctionReturn(0);
6995 }
6996 
6997 #undef __FUNCT__
6998 #define __FUNCT__ "CellRefinerCreateSF"
6999 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7000 {
7001   PetscSF            sf, sfNew, sfProcess;
7002   IS                 processRanks;
7003   MPI_Datatype       depthType;
7004   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
7005   const PetscInt    *localPoints, *neighbors;
7006   const PetscSFNode *remotePoints;
7007   PetscInt          *localPointsNew;
7008   PetscSFNode       *remotePointsNew;
7009   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rdepthMaxOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
7010   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eStartNew, eEnd, eMax, r, n;
7011   PetscErrorCode     ierr;
7012 
7013   PetscFunctionBegin;
7014   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
7015   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7016   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7017   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7018   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7019   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7020   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7021   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
7022   switch (refiner) {
7023   case 3:
7024     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7025     cMax = PetscMin(cEnd, cMax);
7026     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7027     fMax = PetscMin(fEnd, fMax);
7028   }
7029   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
7030   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
7031   /* Caculate size of new SF */
7032   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
7033   if (numRoots < 0) PetscFunctionReturn(0);
7034   for (l = 0; l < numLeaves; ++l) {
7035     const PetscInt p = localPoints[l];
7036 
7037     switch (refiner) {
7038     case 1:
7039       /* Simplicial 2D */
7040       if ((p >= vStart) && (p < vEnd)) {
7041         /* Old vertices stay the same */
7042         ++numLeavesNew;
7043       } else if ((p >= fStart) && (p < fEnd)) {
7044         /* Old faces add new faces and vertex */
7045         numLeavesNew += 1 + 2;
7046       } else if ((p >= cStart) && (p < cEnd)) {
7047         /* Old cells add new cells and interior faces */
7048         numLeavesNew += 4 + 3;
7049       }
7050       break;
7051     case 2:
7052       /* Hex 2D */
7053       if ((p >= vStart) && (p < vEnd)) {
7054         /* Old vertices stay the same */
7055         ++numLeavesNew;
7056       } else if ((p >= fStart) && (p < fEnd)) {
7057         /* Old faces add new faces and vertex */
7058         numLeavesNew += 1 + 2;
7059       } else if ((p >= cStart) && (p < cEnd)) {
7060         /* Old cells add new cells and interior faces */
7061         numLeavesNew += 4 + 4;
7062       }
7063       break;
7064     default:
7065       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7066     }
7067   }
7068   /* Communicate depthSizes for each remote rank */
7069   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
7070   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
7071   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
7072   ierr = PetscMalloc7(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthMaxOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);CHKERRQ(ierr);
7073   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
7074   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
7075   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7076   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
7077   for (n = 0; n < numNeighbors; ++n) {
7078     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
7079   }
7080   depthSizeOld[depth]   = cMax;
7081   depthSizeOld[0]       = vMax;
7082   depthSizeOld[depth-1] = fMax;
7083   depthSizeOld[1]       = eMax;
7084   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7085   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthMaxOld);CHKERRQ(ierr);
7086   depthSizeOld[depth]   = cEnd - cStart;
7087   depthSizeOld[0]       = vEnd - vStart;
7088   depthSizeOld[depth-1] = fEnd - fStart;
7089   depthSizeOld[1]       = eEnd - eStart;
7090   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7091   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
7092   for (n = 0; n < numNeighbors; ++n) {
7093     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
7094   }
7095   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
7096   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
7097   /* Calculate new point SF */
7098   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
7099   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
7100   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
7101   for (l = 0, m = 0; l < numLeaves; ++l) {
7102     PetscInt    p     = localPoints[l];
7103     PetscInt    rp    = remotePoints[l].index, n;
7104     PetscMPIInt rrank = remotePoints[l].rank;
7105 
7106     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
7107     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
7108     switch (refiner) {
7109     case 1:
7110       /* Simplicial 2D */
7111       if ((p >= vStart) && (p < vEnd)) {
7112         /* Old vertices stay the same */
7113         localPointsNew[m]        = vStartNew     + (p  - vStart);
7114         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7115         remotePointsNew[m].rank  = rrank;
7116         ++m;
7117       } else if ((p >= fStart) && (p < fEnd)) {
7118         /* Old faces add new faces and vertex */
7119         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7120         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7121         remotePointsNew[m].rank  = rrank;
7122         ++m;
7123         for (r = 0; r < 2; ++r, ++m) {
7124           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7125           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7126           remotePointsNew[m].rank  = rrank;
7127         }
7128       } else if ((p >= cStart) && (p < cEnd)) {
7129         /* Old cells add new cells and interior faces */
7130         for (r = 0; r < 4; ++r, ++m) {
7131           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7132           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7133           remotePointsNew[m].rank  = rrank;
7134         }
7135         for (r = 0; r < 3; ++r, ++m) {
7136           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
7137           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
7138           remotePointsNew[m].rank  = rrank;
7139         }
7140       }
7141       break;
7142     case 2:
7143       /* Hex 2D */
7144       if ((p >= vStart) && (p < vEnd)) {
7145         /* Old vertices stay the same */
7146         localPointsNew[m]        = vStartNew     + (p  - vStart);
7147         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7148         remotePointsNew[m].rank  = rrank;
7149         ++m;
7150       } else if ((p >= fStart) && (p < fEnd)) {
7151         /* Old faces add new faces and vertex */
7152         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7153         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7154         remotePointsNew[m].rank  = rrank;
7155         ++m;
7156         for (r = 0; r < 2; ++r, ++m) {
7157           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7158           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7159           remotePointsNew[m].rank  = rrank;
7160         }
7161       } else if ((p >= cStart) && (p < cEnd)) {
7162         /* Old cells add new cells and interior faces */
7163         for (r = 0; r < 4; ++r, ++m) {
7164           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7165           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7166           remotePointsNew[m].rank  = rrank;
7167         }
7168         for (r = 0; r < 4; ++r, ++m) {
7169           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
7170           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
7171           remotePointsNew[m].rank  = rrank;
7172         }
7173       }
7174       break;
7175     case 3:
7176       /* Hybrid simplicial 2D */
7177       if ((p >= vStart) && (p < vEnd)) {
7178         /* Old vertices stay the same */
7179         localPointsNew[m]        = vStartNew     + (p  - vStart);
7180         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
7181         remotePointsNew[m].rank  = rrank;
7182         ++m;
7183       } else if ((p >= fStart) && (p < fMax)) {
7184         /* Old interior faces add new faces and vertex */
7185         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
7186         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
7187         remotePointsNew[m].rank  = rrank;
7188         ++m;
7189         for (r = 0; r < 2; ++r, ++m) {
7190           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
7191           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
7192           remotePointsNew[m].rank  = rrank;
7193         }
7194       } else if ((p >= fMax) && (p < fEnd)) {
7195         /* Old hybrid faces stay the same */
7196         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - fMax);
7197         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rdepthMaxOld[n*(depth+1)+depth-1]);
7198         remotePointsNew[m].rank  = rrank;
7199         ++m;
7200       } else if ((p >= cStart) && (p < cMax)) {
7201         /* Old interior cells add new cells and interior faces */
7202         for (r = 0; r < 4; ++r, ++m) {
7203           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7204           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7205           remotePointsNew[m].rank  = rrank;
7206         }
7207         for (r = 0; r < 3; ++r, ++m) {
7208           localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (p  - cStart)*3     + r;
7209           remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rp - rcStart[n])*3 + r;
7210           remotePointsNew[m].rank  = rrank;
7211         }
7212       } else if ((p >= cStart) && (p < cMax)) {
7213         /* Old hybrid cells add new cells and hybrid face */
7214         for (r = 0; r < 2; ++r, ++m) {
7215           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
7216           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
7217           remotePointsNew[m].rank  = rrank;
7218         }
7219         localPointsNew[m]        = fStartNew     + (fMax                              - fStart)*2     + (cMax                            - cStart)*3     + (p  - cMax);
7220         remotePointsNew[m].index = rfStartNew[n] + (rdepthMaxOld[n*(depth+1)+depth-1] - rfStart[n])*2 + (rdepthMaxOld[n*(depth+1)+depth] - rcStart[n])*3 + (rp - rdepthMaxOld[n*(depth+1)+depth]);
7221         remotePointsNew[m].rank  = rrank;
7222         ++m;
7223       }
7224       break;
7225     default:
7226       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7227     }
7228   }
7229   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
7230   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
7231   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
7232   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
7233   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
7234   PetscFunctionReturn(0);
7235 }
7236 
7237 #undef __FUNCT__
7238 #define __FUNCT__ "CellRefinerCreateLabels"
7239 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
7240 {
7241   PetscInt       numLabels, l;
7242   PetscInt       newp, cStart, cStartNew, cEnd, cMax, vStart, vStartNew, vEnd, vMax, fStart, fStartNew, fEnd, fMax, eStart, eEnd, eMax, r;
7243   PetscErrorCode ierr;
7244 
7245   PetscFunctionBegin;
7246   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7247   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
7248   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7249   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
7250   cStartNew = 0;
7251   vStartNew = depthSize[2];
7252   fStartNew = depthSize[2] + depthSize[0];
7253   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
7254   ierr = DMPlexGetHybridBounds(dm, &cMax, &fMax, &eMax, &vMax);CHKERRQ(ierr);
7255   switch (refiner) {
7256   case 3:
7257     if (cMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No cell maximum specified in hybrid mesh");
7258     cMax = PetscMin(cEnd, cMax);
7259     if (fMax < 0) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "No face maximum specified in hybrid mesh");
7260     fMax = PetscMin(fEnd, fMax);
7261   }
7262   for (l = 0; l < numLabels; ++l) {
7263     DMLabel         label, labelNew;
7264     const char     *lname;
7265     PetscBool       isDepth;
7266     IS              valueIS;
7267     const PetscInt *values;
7268     PetscInt        numValues, val;
7269 
7270     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
7271     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
7272     if (isDepth) continue;
7273     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
7274     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
7275     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
7276     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
7277     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
7278     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
7279     for (val = 0; val < numValues; ++val) {
7280       IS              pointIS;
7281       const PetscInt *points;
7282       PetscInt        numPoints, n;
7283 
7284       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
7285       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
7286       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
7287       for (n = 0; n < numPoints; ++n) {
7288         const PetscInt p = points[n];
7289         switch (refiner) {
7290         case 1:
7291           /* Simplicial 2D */
7292           if ((p >= vStart) && (p < vEnd)) {
7293             /* Old vertices stay the same */
7294             newp = vStartNew + (p - vStart);
7295             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7296           } else if ((p >= fStart) && (p < fEnd)) {
7297             /* Old faces add new faces and vertex */
7298             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7299             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7300             for (r = 0; r < 2; ++r) {
7301               newp = fStartNew + (p - fStart)*2 + r;
7302               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7303             }
7304           } else if ((p >= cStart) && (p < cEnd)) {
7305             /* Old cells add new cells and interior faces */
7306             for (r = 0; r < 4; ++r) {
7307               newp = cStartNew + (p - cStart)*4 + r;
7308               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7309             }
7310             for (r = 0; r < 3; ++r) {
7311               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7312               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7313             }
7314           }
7315           break;
7316         case 2:
7317           /* Hex 2D */
7318           if ((p >= vStart) && (p < vEnd)) {
7319             /* Old vertices stay the same */
7320             newp = vStartNew + (p - vStart);
7321             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7322           } else if ((p >= fStart) && (p < fEnd)) {
7323             /* Old faces add new faces and vertex */
7324             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7325             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7326             for (r = 0; r < 2; ++r) {
7327               newp = fStartNew + (p - fStart)*2 + r;
7328               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7329             }
7330           } else if ((p >= cStart) && (p < cEnd)) {
7331             /* Old cells add new cells and interior faces and vertex */
7332             for (r = 0; r < 4; ++r) {
7333               newp = cStartNew + (p - cStart)*4 + r;
7334               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7335             }
7336             for (r = 0; r < 4; ++r) {
7337               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
7338               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7339             }
7340             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
7341             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7342           }
7343           break;
7344         case 3:
7345           /* Hybrid simplicial 2D */
7346           if ((p >= vStart) && (p < vEnd)) {
7347             /* Old vertices stay the same */
7348             newp = vStartNew + (p - vStart);
7349             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7350           } else if ((p >= fStart) && (p < fMax)) {
7351             /* Old interior faces add new faces and vertex */
7352             newp = vStartNew + (vEnd - vStart) + (p - fStart);
7353             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7354             for (r = 0; r < 2; ++r) {
7355               newp = fStartNew + (p - fStart)*2 + r;
7356               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7357             }
7358           } else if ((p >= fMax) && (p < fEnd)) {
7359             /* Old hybrid faces stay the same */
7360             newp = fStartNew + (fMax - fStart)*2 + (p - fMax);
7361             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7362           } else if ((p >= cStart) && (p < cMax)) {
7363             /* Old interior cells add new cells and interior faces */
7364             for (r = 0; r < 4; ++r) {
7365               newp = cStartNew + (p - cStart)*4 + r;
7366               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7367             }
7368             for (r = 0; r < 3; ++r) {
7369               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
7370               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7371             }
7372           } else if ((p >= cMax) && (p < cEnd)) {
7373             /* Old hybrid cells add new cells and hybrid face */
7374             for (r = 0; r < 2; ++r) {
7375               newp = cStartNew + (cMax - cStart)*4 + (p - cMax)*2 + r;
7376               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7377             }
7378             newp = fStartNew + (fMax - fStart)*2 + (cMax - cStart)*3 + (p - cMax);
7379             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
7380           }
7381           break;
7382         default:
7383           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
7384         }
7385       }
7386       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
7387       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
7388     }
7389     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
7390     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
7391     if (0) {
7392       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
7393       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7394       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
7395     }
7396   }
7397   PetscFunctionReturn(0);
7398 }
7399 
7400 #undef __FUNCT__
7401 #define __FUNCT__ "DMPlexRefine_Uniform"
7402 /* This will only work for interpolated meshes */
7403 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
7404 {
7405   DM              rdm;
7406   PetscInt       *depthSize;
7407   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
7408   PetscErrorCode  ierr;
7409 
7410   PetscFunctionBegin;
7411   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
7412   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
7413   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7414   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
7415   /* Calculate number of new points of each depth */
7416   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
7417   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
7418   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
7419   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
7420   /* Step 1: Set chart */
7421   for (d = 0; d <= depth; ++d) {
7422     pEnd += depthSize[d];
7423   }
7424   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
7425   /* Step 2: Set cone/support sizes */
7426   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7427   /* Step 3: Setup refined DM */
7428   ierr = DMSetUp(rdm);CHKERRQ(ierr);
7429   /* Step 4: Set cones and supports */
7430   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7431   /* Step 5: Stratify */
7432   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
7433   /* Step 6: Set coordinates for vertices */
7434   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7435   /* Step 7: Create pointSF */
7436   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7437   /* Step 8: Create labels */
7438   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
7439   ierr = PetscFree(depthSize);CHKERRQ(ierr);
7440 
7441   *dmRefined = rdm;
7442 #if 0
7443   DM_Plex *mesh = (DM_Plex *) dm->data;
7444   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
7445   /* ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize())); */
7446 
7447   PetscFunctionBegin;
7448   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7449   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
7450   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7451   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
7452   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
7453 
7454   /* Count number of new cells which are normal and extra */
7455   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
7456   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
7457   for (c = cStart; c < cEnd2; ++c) {
7458     PetscInt n;
7459     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7460     newNumCellsNormal += n;
7461   }
7462   for (c = cEnd2; c < cEnd; ++c) {
7463     PetscInt n;
7464     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); /* refiner.numNewCells */
7465     newNumCellsExtra += n;
7466   }
7467   newNumCells = newNumCellsNormal + newNumCellsExtra;
7468   /* Count number of new vertices which are normal and extra */
7469   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
7470   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
7471   for (c = cStart; c < cEnd; ++c) {
7472     PetscInt *closure = PETSC_NULL;
7473     PetscInt  closureSize, numCorners = 0, p;
7474 
7475     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7476     for (p = 0; p < closureSize*2; p += 2) {
7477       const PetscInt point = closure[p];
7478       if ((point >= vStart) && (point < vEnd)) {
7479         closure[numCorners++] = point;
7480       }
7481     }
7482     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCell */
7483     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7484   }
7485   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
7486   for (c = cEnd2; c < cEnd; ++c) {
7487     PetscInt *closure = PETSC_NULL;
7488     PetscInt  closureSize, numCorners = 0, p;
7489 
7490     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7491     for (p = 0; p < closureSize*2; p += 2) {
7492       const PetscInt point = closure[p];
7493       if ((point >= vStart) && (point < vEnd)) {
7494         closure[numCorners++] = point;
7495       }
7496     }
7497     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); /* refiner.splitCellUncensored */
7498     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7499   } /* for */
7500   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
7501   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
7502 
7503 #if 1
7504   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
7505   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
7506   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
7507   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
7508   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
7509   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
7510   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
7511   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
7512   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
7513   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
7514   ierr = PetscSynchronizedFlush(comm);
7515 #endif
7516 
7517   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
7518   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
7519   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
7520   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
7521   ierr = DMPlexGetHybridBounds(*dmRefined, newNumCellsNormal, PETSC_NULL, PETSC_NULL, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
7522   /* Set cone and support sizes for new normal cells */
7523   PetscInt newCell = 0;
7524   for (c = cStart; c < cEnd2; ++c) {
7525     PetscInt coneSize, n, i;
7526 
7527     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7528     ierr = CellRefinerGetNumSubcells(refiner, c, &n); /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7529     for (i = 0; i < n; ++i, ++newCell) {
7530       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
7531     }
7532 
7533     PetscInt *closure = PETSC_NULL;
7534     PetscInt  closureSize, numCorners = 0, p;
7535 
7536     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7537     for (p = 0; p < closureSize*2; p += 2) {
7538       const PetscInt point = closure[p];
7539       if ((point >= vStart) && (point < vEnd)) {
7540         closure[numCorners++] = point;
7541       }
7542     }
7543     /* ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); */ /* refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh); */
7544     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
7545   }
7546 
7547   /* Reset current new cell value and loop over censored cells. */
7548   curNewCell = _orderNewMesh->cellsCensored().min();
7549   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7550   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7551     /* Set new cone and support sizes */
7552     cV.clear();
7553     sieve->cone(*c_iter, cV);
7554     const point_type* cone = cV.getPoints();
7555     const int coneSize = cV.getSize();
7556 
7557     const point_type* newCells;
7558     int numNewCells = 0;
7559     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7560 
7561     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7562       newSieve->setConeSize(curNewCell, coneSize);
7563       for (int iVertex=0; iVertex < coneSize; ++iVertex) {
7564         newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
7565       } /* for */
7566     } /* for */
7567   } /* for */
7568   newSieve->allocate();
7569 
7570   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
7571 
7572   /* Create refined cells in new sieve. */
7573   curNewCell = _orderNewMesh->cellsNormal().min();
7574   oldCellsEnd = _orderOldMesh->cellsNormal().end();
7575   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
7576     cV.clear();
7577     sieve->cone(*c_iter, cV);
7578     const point_type *cone = cV.getPoints();
7579     const int coneSize = cV.getSize();
7580 
7581     const point_type* newCells;
7582     int numNewCells = 0;
7583     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7584 
7585     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7586       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7587     } /* for */
7588   } /* for */
7589   curNewCell = _orderNewMesh->cellsCensored().min();
7590   oldCellsEnd = _orderOldMesh->cellsCensored().end();
7591   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
7592     cV.clear();
7593     sieve->cone(*c_iter, cV);
7594     const point_type *cone = cV.getPoints();
7595     const int coneSize = cV.getSize();
7596 
7597     const point_type* newCells;
7598     int numNewCells = 0;
7599     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
7600 
7601     for (int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
7602       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
7603     } /* for */
7604   } /* for */
7605   newSieve->symmetrize();
7606 
7607   /* Set coordinates in refined mesh. */
7608   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
7609   assert(!coordinates.isNull());
7610   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
7611   assert(!newCoordinates.isNull());
7612 
7613   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
7614   assert(vertices->size() > 0);
7615   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
7616   assert(spaceDim > 0);
7617   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
7618 
7619   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
7620   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
7621     newCoordinates->setFiberDimension(*v_iter, spaceDim);
7622   } /* for */
7623   newCoordinates->allocatePoint();
7624 
7625   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
7626   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7627     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7628     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7629   } /* for */
7630   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
7631   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
7632     /*std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl; */
7633     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
7634   } /* for */
7635 
7636   refiner.setCoordsNewVertices(newCoordinates, coordinates);
7637 
7638   /* Create sensored depth */
7639   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
7640   assert(!censoredLabel.isNull());
7641 
7642   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
7643 
7644   newSieve->roots(depthVisitor);
7645   while (depthVisitor.isModified()) {
7646     /* FIX: Avoid the copy here somehow by fixing the traversal */
7647     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
7648 
7649     depthVisitor.clear();
7650     newSieve->support(modifiedPoints, depthVisitor);
7651   } /* while */
7652   /* Stratify refined mesh */
7653   /* Calculate new point SF */
7654   _calcNewOverlap(newMesh, mesh, refiner);
7655   /* Calculate new labels */
7656   _createLabels(newMesh, mesh, refiner);
7657 #endif
7658   PetscFunctionReturn(0);
7659 }
7660 
7661 #undef __FUNCT__
7662 #define __FUNCT__ "DMPlexSetRefinementUniform"
7663 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
7664 {
7665   DM_Plex *mesh = (DM_Plex *) dm->data;
7666 
7667   PetscFunctionBegin;
7668   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7669   mesh->refinementUniform = refinementUniform;
7670   PetscFunctionReturn(0);
7671 }
7672 
7673 #undef __FUNCT__
7674 #define __FUNCT__ "DMPlexGetRefinementUniform"
7675 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
7676 {
7677   DM_Plex *mesh = (DM_Plex *) dm->data;
7678 
7679   PetscFunctionBegin;
7680   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7681   PetscValidPointer(refinementUniform,  2);
7682   *refinementUniform = mesh->refinementUniform;
7683   PetscFunctionReturn(0);
7684 }
7685 
7686 #undef __FUNCT__
7687 #define __FUNCT__ "DMPlexSetRefinementLimit"
7688 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
7689 {
7690   DM_Plex *mesh = (DM_Plex *) dm->data;
7691 
7692   PetscFunctionBegin;
7693   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7694   mesh->refinementLimit = refinementLimit;
7695   PetscFunctionReturn(0);
7696 }
7697 
7698 #undef __FUNCT__
7699 #define __FUNCT__ "DMPlexGetRefinementLimit"
7700 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
7701 {
7702   DM_Plex *mesh = (DM_Plex *) dm->data;
7703 
7704   PetscFunctionBegin;
7705   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7706   PetscValidPointer(refinementLimit,  2);
7707   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
7708   *refinementLimit = mesh->refinementLimit;
7709   PetscFunctionReturn(0);
7710 }
7711 
7712 #undef __FUNCT__
7713 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
7714 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
7715 {
7716   PetscInt       dim, cStart, coneSize, cMax;
7717   PetscErrorCode ierr;
7718 
7719   PetscFunctionBegin;
7720   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7721   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
7722   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
7723   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
7724   switch (dim) {
7725   case 2:
7726     switch (coneSize) {
7727     case 3:
7728       if (cMax >= 0) {
7729         *cellRefiner = 3; /* Hybrid */
7730       } else {
7731         *cellRefiner = 1; /* Triangular */
7732       }
7733       break;
7734     case 4:
7735       if (cMax >= 0) {
7736         *cellRefiner = 4; /* Hybrid */
7737       } else {
7738         *cellRefiner = 2; /* Quadrilateral */
7739       }
7740       break;
7741     default:
7742       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
7743     }
7744     break;
7745   default:
7746     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
7747   }
7748   PetscFunctionReturn(0);
7749 }
7750 
7751 #undef __FUNCT__
7752 #define __FUNCT__ "DMRefine_Plex"
7753 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
7754 {
7755   PetscReal      refinementLimit;
7756   PetscInt       dim, cStart, cEnd;
7757   char           genname[1024], *name = PETSC_NULL;
7758   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
7759   PetscErrorCode ierr;
7760 
7761   PetscFunctionBegin;
7762   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
7763   if (isUniform) {
7764     CellRefiner cellRefiner;
7765 
7766     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
7767     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
7768     PetscFunctionReturn(0);
7769   }
7770   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
7771   if (refinementLimit == 0.0) PetscFunctionReturn(0);
7772   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7773   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7774   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
7775   if (flg) {name = genname;}
7776   if (name) {
7777     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
7778     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
7779     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
7780   }
7781   switch (dim) {
7782   case 2:
7783     if (!name || isTriangle) {
7784 #if defined(PETSC_HAVE_TRIANGLE)
7785       double  *maxVolumes;
7786       PetscInt c;
7787 
7788       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7789       for (c = 0; c < cEnd-cStart; ++c) {
7790         maxVolumes[c] = refinementLimit;
7791       }
7792       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7793 #else
7794       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
7795 #endif
7796     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
7797     break;
7798   case 3:
7799     if (!name || isCTetgen) {
7800 #if defined(PETSC_HAVE_CTETGEN)
7801       PetscReal *maxVolumes;
7802       PetscInt   c;
7803 
7804       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
7805       for (c = 0; c < cEnd-cStart; ++c) {
7806         maxVolumes[c] = refinementLimit;
7807       }
7808       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7809 #else
7810       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
7811 #endif
7812     } else if (isTetgen) {
7813 #if defined(PETSC_HAVE_TETGEN)
7814       double  *maxVolumes;
7815       PetscInt c;
7816 
7817       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
7818       for (c = 0; c < cEnd-cStart; ++c) {
7819         maxVolumes[c] = refinementLimit;
7820       }
7821       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
7822 #else
7823       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
7824 #endif
7825     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
7826     break;
7827   default:
7828     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
7829   }
7830   PetscFunctionReturn(0);
7831 }
7832 
7833 #undef __FUNCT__
7834 #define __FUNCT__ "DMPlexGetDepth"
7835 /*@
7836   DMPlexGetDepth - get the number of strata
7837 
7838   Not Collective
7839 
7840   Input Parameters:
7841 . dm           - The DMPlex object
7842 
7843   Output Parameters:
7844 . depth - number of strata
7845 
7846   Level: developer
7847 
7848   Notes:
7849   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
7850 
7851 .keywords: mesh, points
7852 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
7853 @*/
7854 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
7855 {
7856   PetscInt       d;
7857   PetscErrorCode ierr;
7858 
7859   PetscFunctionBegin;
7860   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7861   PetscValidPointer(depth, 2);
7862   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
7863   *depth = d-1;
7864   PetscFunctionReturn(0);
7865 }
7866 
7867 #undef __FUNCT__
7868 #define __FUNCT__ "DMPlexGetDepthStratum"
7869 /*@
7870   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
7871 
7872   Not Collective
7873 
7874   Input Parameters:
7875 + dm           - The DMPlex object
7876 - stratumValue - The requested depth
7877 
7878   Output Parameters:
7879 + start - The first point at this depth
7880 - end   - One beyond the last point at this depth
7881 
7882   Level: developer
7883 
7884 .keywords: mesh, points
7885 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
7886 @*/
7887 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7888 {
7889   DM_Plex    *mesh = (DM_Plex *) dm->data;
7890   DMLabel        next = mesh->labels;
7891   PetscBool      flg  = PETSC_FALSE;
7892   PetscInt       depth;
7893   PetscErrorCode ierr;
7894 
7895   PetscFunctionBegin;
7896   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7897   if (stratumValue < 0) {
7898     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7899     PetscFunctionReturn(0);
7900   } else {
7901     PetscInt pStart, pEnd;
7902 
7903     if (start) {*start = 0;}
7904     if (end)   {*end   = 0;}
7905     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7906     if (pStart == pEnd) {PetscFunctionReturn(0);}
7907   }
7908   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7909   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7910   /* We should have a generic GetLabel() and a Label class */
7911   while (next) {
7912     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7913     if (flg) break;
7914     next = next->next;
7915   }
7916   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7917   depth = stratumValue;
7918   if ((depth < 0) || (depth >= next->numStrata)) {
7919     if (start) {*start = 0;}
7920     if (end)   {*end   = 0;}
7921   } else {
7922     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7923     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7924   }
7925   PetscFunctionReturn(0);
7926 }
7927 
7928 #undef __FUNCT__
7929 #define __FUNCT__ "DMPlexGetHeightStratum"
7930 /*@
7931   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
7932 
7933   Not Collective
7934 
7935   Input Parameters:
7936 + dm           - The DMPlex object
7937 - stratumValue - The requested height
7938 
7939   Output Parameters:
7940 + start - The first point at this height
7941 - end   - One beyond the last point at this height
7942 
7943   Level: developer
7944 
7945 .keywords: mesh, points
7946 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
7947 @*/
7948 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end)
7949 {
7950   DM_Plex        *mesh = (DM_Plex *) dm->data;
7951   DMLabel        next = mesh->labels;
7952   PetscBool      flg  = PETSC_FALSE;
7953   PetscInt       depth;
7954   PetscErrorCode ierr;
7955 
7956   PetscFunctionBegin;
7957   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7958   if (stratumValue < 0) {
7959     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
7960   } else {
7961     PetscInt pStart, pEnd;
7962 
7963     if (start) {*start = 0;}
7964     if (end)   {*end   = 0;}
7965     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
7966     if (pStart == pEnd) {PetscFunctionReturn(0);}
7967   }
7968   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
7969   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
7970   /* We should have a generic GetLabel() and a Label class */
7971   while (next) {
7972     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
7973     if (flg) break;
7974     next = next->next;
7975   }
7976   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
7977   depth = next->stratumValues[next->numStrata-1] - stratumValue;
7978   if ((depth < 0) || (depth >= next->numStrata)) {
7979     if (start) {*start = 0;}
7980     if (end)   {*end   = 0;}
7981   } else {
7982     if (start) {*start = next->points[next->stratumOffsets[depth]];}
7983     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
7984   }
7985   PetscFunctionReturn(0);
7986 }
7987 
7988 #undef __FUNCT__
7989 #define __FUNCT__ "DMPlexCreateSectionInitial"
7990 /* Set the number of dof on each point and separate by fields */
7991 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section)
7992 {
7993   PetscInt      *numDofTot;
7994   PetscInt       pStart = 0, pEnd = 0;
7995   PetscInt       p, d, f;
7996   PetscErrorCode ierr;
7997 
7998   PetscFunctionBegin;
7999   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
8000   for (d = 0; d <= dim; ++d) {
8001     numDofTot[d] = 0;
8002     for (f = 0; f < numFields; ++f) {
8003       numDofTot[d] += numDof[f*(dim+1)+d];
8004     }
8005   }
8006   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
8007   if (numFields > 0) {
8008     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
8009     if (numComp) {
8010       for (f = 0; f < numFields; ++f) {
8011         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
8012       }
8013     }
8014   }
8015   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
8016   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
8017   for (d = 0; d <= dim; ++d) {
8018     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
8019     for (p = pStart; p < pEnd; ++p) {
8020       for (f = 0; f < numFields; ++f) {
8021         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
8022       }
8023       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
8024     }
8025   }
8026   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
8027   PetscFunctionReturn(0);
8028 }
8029 
8030 #undef __FUNCT__
8031 #define __FUNCT__ "DMPlexCreateSectionBCDof"
8032 /* Set the number of dof on each point and separate by fields
8033    If constDof is PETSC_DETERMINE, constrain every dof on the point
8034 */
8035 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section)
8036 {
8037   PetscInt       numFields;
8038   PetscInt       bc;
8039   PetscErrorCode ierr;
8040 
8041   PetscFunctionBegin;
8042   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8043   for (bc = 0; bc < numBC; ++bc) {
8044     PetscInt        field = 0;
8045     const PetscInt *idx;
8046     PetscInt        n, i;
8047 
8048     if (numFields) {field = bcField[bc];}
8049     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
8050     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8051     for (i = 0; i < n; ++i) {
8052       const PetscInt p = idx[i];
8053       PetscInt       numConst = constDof;
8054 
8055       /* Constrain every dof on the point */
8056       if (numConst < 0) {
8057         if (numFields) {
8058           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
8059         } else {
8060           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
8061         }
8062       }
8063       if (numFields) {
8064         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
8065       }
8066       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
8067     }
8068     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
8069   }
8070   PetscFunctionReturn(0);
8071 }
8072 
8073 #undef __FUNCT__
8074 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
8075 /* Set the constrained indices on each point and separate by fields */
8076 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section)
8077 {
8078   PetscInt      *maxConstraints;
8079   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
8080   PetscErrorCode ierr;
8081 
8082   PetscFunctionBegin;
8083   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8084   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8085   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
8086   for (f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
8087   for (p = pStart; p < pEnd; ++p) {
8088     PetscInt cdof;
8089 
8090     if (numFields) {
8091       for (f = 0; f < numFields; ++f) {
8092         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
8093         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
8094       }
8095     } else {
8096       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8097       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
8098     }
8099   }
8100   for (f = 0; f < numFields; ++f) {
8101     maxConstraints[numFields] += maxConstraints[f];
8102   }
8103   if (maxConstraints[numFields]) {
8104     PetscInt *indices;
8105 
8106     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8107     for (p = pStart; p < pEnd; ++p) {
8108       PetscInt cdof, d;
8109 
8110       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8111       if (cdof) {
8112         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
8113         if (numFields) {
8114           PetscInt numConst = 0, foff = 0;
8115 
8116           for (f = 0; f < numFields; ++f) {
8117             PetscInt cfdof, fdof;
8118 
8119             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8120             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
8121             /* Change constraint numbering from absolute local dof number to field relative local dof number */
8122             for (d = 0; d < cfdof; ++d) {
8123               indices[numConst+d] = d;
8124             }
8125             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
8126             for (d = 0; d < cfdof; ++d) {
8127               indices[numConst+d] += foff;
8128             }
8129             numConst += cfdof;
8130             foff     += fdof;
8131           }
8132           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8133         } else {
8134           for (d = 0; d < cdof; ++d) {
8135             indices[d] = d;
8136           }
8137         }
8138         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8139       }
8140     }
8141     ierr = PetscFree(indices);CHKERRQ(ierr);
8142   }
8143   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
8144   PetscFunctionReturn(0);
8145 }
8146 
8147 #undef __FUNCT__
8148 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
8149 /* Set the constrained field indices on each point */
8150 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section)
8151 {
8152   const PetscInt *points, *indices;
8153   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
8154   PetscErrorCode  ierr;
8155 
8156   PetscFunctionBegin;
8157   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8158   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
8159 
8160   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
8161   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
8162   if (!constraintIndices) {
8163     PetscInt *idx, i;
8164 
8165     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8166     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
8167     for (i = 0; i < maxDof; ++i) {idx[i] = i;}
8168     for (p = 0; p < numPoints; ++p) {
8169       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
8170     }
8171     ierr = PetscFree(idx);CHKERRQ(ierr);
8172   } else {
8173     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
8174     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
8175     for (p = 0; p < numPoints; ++p) {
8176       PetscInt fcdof;
8177 
8178       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
8179       if (fcdof != numConstraints) SETERRQ4(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Section point %d field %d has %d constraints, but yo ugave %d indices", p, field, fcdof, numConstraints);
8180       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
8181     }
8182     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
8183   }
8184   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
8185   PetscFunctionReturn(0);
8186 }
8187 
8188 #undef __FUNCT__
8189 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
8190 /* Set the constrained indices on each point and separate by fields */
8191 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section)
8192 {
8193   PetscInt      *indices;
8194   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
8195   PetscErrorCode ierr;
8196 
8197   PetscFunctionBegin;
8198   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
8199   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
8200   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8201   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
8202   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8203   for (p = pStart; p < pEnd; ++p) {
8204     PetscInt cdof, d;
8205 
8206     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
8207     if (cdof) {
8208       PetscInt numConst = 0, foff = 0;
8209 
8210       for (f = 0; f < numFields; ++f) {
8211         const PetscInt *fcind;
8212         PetscInt        fdof, fcdof;
8213 
8214         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
8215         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
8216         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
8217         /* Change constraint numbering from field relative local dof number to absolute local dof number */
8218         for (d = 0; d < fcdof; ++d) {
8219           indices[numConst+d] = fcind[d]+foff;
8220         }
8221         foff     += fdof;
8222         numConst += fcdof;
8223       }
8224       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
8225       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
8226     }
8227   }
8228   ierr = PetscFree(indices);CHKERRQ(ierr);
8229   PetscFunctionReturn(0);
8230 }
8231 
8232 #undef __FUNCT__
8233 #define __FUNCT__ "DMPlexCreateSection"
8234 /*@C
8235   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
8236 
8237   Not Collective
8238 
8239   Input Parameters:
8240 + dm        - The DMPlex object
8241 . dim       - The spatial dimension of the problem
8242 . numFields - The number of fields in the problem
8243 . numComp   - An array of size numFields that holds the number of components for each field
8244 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
8245 . numBC     - The number of boundary conditions
8246 . bcField   - An array of size numBC giving the field number for each boundry condition
8247 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
8248 
8249   Output Parameter:
8250 . section - The PetscSection object
8251 
8252   Notes: numDof[f*(dim+1)+d] gives the number of dof for field f on sieve points of dimension d. For instance, numDof[1] is the
8253   nubmer of dof for field 0 on each edge.
8254 
8255   Level: developer
8256 
8257 .keywords: mesh, elements
8258 .seealso: DMPlexCreate(), PetscSectionCreate()
8259 @*/
8260 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section)
8261 {
8262   PetscErrorCode ierr;
8263 
8264   PetscFunctionBegin;
8265   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
8266   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
8267   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
8268   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
8269   {
8270     PetscBool view = PETSC_FALSE;
8271 
8272     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
8273     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
8274   }
8275   PetscFunctionReturn(0);
8276 }
8277 
8278 #undef __FUNCT__
8279 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
8280 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm)
8281 {
8282   PetscSection   section;
8283   PetscErrorCode ierr;
8284 
8285   PetscFunctionBegin;
8286   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
8287   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
8288   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
8289   PetscFunctionReturn(0);
8290 }
8291 
8292 #undef __FUNCT__
8293 #define __FUNCT__ "DMPlexGetCoordinateSection"
8294 /*@
8295   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
8296 
8297   Not Collective
8298 
8299   Input Parameter:
8300 . dm - The DMPlex object
8301 
8302   Output Parameter:
8303 . section - The PetscSection object
8304 
8305   Level: intermediate
8306 
8307 .keywords: mesh, coordinates
8308 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8309 @*/
8310 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section)
8311 {
8312   DM             cdm;
8313   PetscErrorCode ierr;
8314 
8315   PetscFunctionBegin;
8316   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8317   PetscValidPointer(section, 2);
8318   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8319   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
8320   PetscFunctionReturn(0);
8321 }
8322 
8323 #undef __FUNCT__
8324 #define __FUNCT__ "DMPlexSetCoordinateSection"
8325 /*@
8326   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
8327 
8328   Not Collective
8329 
8330   Input Parameters:
8331 + dm      - The DMPlex object
8332 - section - The PetscSection object
8333 
8334   Level: intermediate
8335 
8336 .keywords: mesh, coordinates
8337 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
8338 @*/
8339 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section)
8340 {
8341   DM             cdm;
8342   PetscErrorCode ierr;
8343 
8344   PetscFunctionBegin;
8345   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8346   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
8347   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
8348   PetscFunctionReturn(0);
8349 }
8350 
8351 #undef __FUNCT__
8352 #define __FUNCT__ "DMPlexGetConeSection"
8353 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section)
8354 {
8355   DM_Plex *mesh = (DM_Plex *) dm->data;
8356 
8357   PetscFunctionBegin;
8358   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8359   if (section) *section = mesh->coneSection;
8360   PetscFunctionReturn(0);
8361 }
8362 
8363 #undef __FUNCT__
8364 #define __FUNCT__ "DMPlexGetCones"
8365 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[])
8366 {
8367   DM_Plex *mesh = (DM_Plex *) dm->data;
8368 
8369   PetscFunctionBegin;
8370   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8371   if (cones) *cones = mesh->cones;
8372   PetscFunctionReturn(0);
8373 }
8374 
8375 #undef __FUNCT__
8376 #define __FUNCT__ "DMPlexGetConeOrientations"
8377 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[])
8378 {
8379   DM_Plex *mesh = (DM_Plex *) dm->data;
8380 
8381   PetscFunctionBegin;
8382   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8383   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
8384   PetscFunctionReturn(0);
8385 }
8386 
8387 #undef __FUNCT__
8388 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
8389 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8390 {
8391   const PetscInt embedDim = 2;
8392   PetscReal      x = PetscRealPart(point[0]);
8393   PetscReal      y = PetscRealPart(point[1]);
8394   PetscReal      v0[2], J[4], invJ[4], detJ;
8395   PetscReal      xi, eta;
8396   PetscErrorCode ierr;
8397 
8398   PetscFunctionBegin;
8399   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8400   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
8401   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
8402 
8403   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
8404     *cell = c;
8405   } else {
8406     *cell = -1;
8407   }
8408   PetscFunctionReturn(0);
8409 }
8410 
8411 #undef __FUNCT__
8412 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
8413 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8414 {
8415   PetscSection       coordSection;
8416   Vec                coordsLocal;
8417   const PetscScalar *coords;
8418   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
8419   PetscReal          x         = PetscRealPart(point[0]);
8420   PetscReal          y         = PetscRealPart(point[1]);
8421   PetscInt           crossings = 0, f;
8422   PetscErrorCode     ierr;
8423 
8424   PetscFunctionBegin;
8425   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8426   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8427   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8428   for (f = 0; f < 4; ++f) {
8429     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
8430     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
8431     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
8432     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
8433     PetscReal slope = (y_j - y_i) / (x_j - x_i);
8434     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
8435     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
8436     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
8437     if ((cond1 || cond2)  && above) ++crossings;
8438   }
8439   if (crossings % 2) {
8440     *cell = c;
8441   } else {
8442     *cell = -1;
8443   }
8444   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8445   PetscFunctionReturn(0);
8446 }
8447 
8448 #undef __FUNCT__
8449 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
8450 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8451 {
8452   const PetscInt embedDim = 3;
8453   PetscReal      v0[3], J[9], invJ[9], detJ;
8454   PetscReal      x = PetscRealPart(point[0]);
8455   PetscReal      y = PetscRealPart(point[1]);
8456   PetscReal      z = PetscRealPart(point[2]);
8457   PetscReal      xi, eta, zeta;
8458   PetscErrorCode ierr;
8459 
8460   PetscFunctionBegin;
8461   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
8462   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
8463   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
8464   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
8465 
8466   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
8467     *cell = c;
8468   } else {
8469     *cell = -1;
8470   }
8471   PetscFunctionReturn(0);
8472 }
8473 
8474 #undef __FUNCT__
8475 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
8476 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
8477 {
8478   PetscSection       coordSection;
8479   Vec                coordsLocal;
8480   const PetscScalar *coords;
8481   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
8482                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
8483   PetscBool          found     = PETSC_TRUE;
8484   PetscInt           f;
8485   PetscErrorCode     ierr;
8486 
8487   PetscFunctionBegin;
8488   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
8489   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8490   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8491   for (f = 0; f < 6; ++f) {
8492     /* Check the point is under plane */
8493     /*   Get face normal */
8494     PetscReal v_i[3];
8495     PetscReal v_j[3];
8496     PetscReal normal[3];
8497     PetscReal pp[3];
8498     PetscReal dot;
8499 
8500     v_i[0]    = PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]);
8501     v_i[1]    = PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]);
8502     v_i[2]    = PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2]);
8503     v_j[0]    = PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]);
8504     v_j[1]    = PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]);
8505     v_j[2]    = PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2]);
8506     normal[0] = v_i[1]*v_j[2] - v_i[2]*v_j[1];
8507     normal[1] = v_i[2]*v_j[0] - v_i[0]*v_j[2];
8508     normal[2] = v_i[0]*v_j[1] - v_i[1]*v_j[0];
8509     pp[0]     = PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]);
8510     pp[1]     = PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]);
8511     pp[2]     = PetscRealPart(coords[faces[f*4+0]*3+2] - point[2]);
8512     dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
8513 
8514     /* Check that projected point is in face (2D location problem) */
8515     if (dot < 0.0) {
8516       found = PETSC_FALSE;
8517       break;
8518     }
8519   }
8520   if (found) {
8521     *cell = c;
8522   } else {
8523     *cell = -1;
8524   }
8525   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
8526   PetscFunctionReturn(0);
8527 }
8528 
8529 #undef __FUNCT__
8530 #define __FUNCT__ "DMLocatePoints_Plex"
8531 /*
8532  Need to implement using the guess
8533 */
8534 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
8535 {
8536   PetscInt       cell = -1/*, guess = -1*/;
8537   PetscInt       bs, numPoints, p;
8538   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
8539   PetscInt      *cells;
8540   PetscScalar   *a;
8541   PetscErrorCode ierr;
8542 
8543   PetscFunctionBegin;
8544   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8545   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8546   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
8547   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8548   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
8549   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
8550   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
8551   if (bs != dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Block size for point vector %d must be the mesh coordinate dimension %d", bs, dim);
8552   numPoints /= bs;
8553   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
8554   for (p = 0; p < numPoints; ++p) {
8555     const PetscScalar *point = &a[p*bs];
8556 
8557     switch (dim) {
8558     case 2:
8559       for (c = cStart; c < cEnd; ++c) {
8560         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8561         switch (coneSize) {
8562         case 3:
8563           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
8564           break;
8565         case 4:
8566           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
8567           break;
8568         default:
8569           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8570         }
8571         if (cell >= 0) break;
8572       }
8573       break;
8574     case 3:
8575       for (c = cStart; c < cEnd; ++c) {
8576         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
8577         switch (coneSize) {
8578         case 4:
8579           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
8580           break;
8581         case 8:
8582           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
8583           break;
8584         default:
8585           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
8586         }
8587         if (cell >= 0) break;
8588       }
8589       break;
8590     default:
8591       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
8592     }
8593     cells[p] = cell;
8594   }
8595   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
8596   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
8597   PetscFunctionReturn(0);
8598 }
8599 
8600 /******************************** FEM Support **********************************/
8601 
8602 #undef __FUNCT__
8603 #define __FUNCT__ "DMPlexVecGetClosure"
8604 /*@C
8605   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
8606 
8607   Not collective
8608 
8609   Input Parameters:
8610 + dm - The DM
8611 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8612 . v - The local vector
8613 - point - The sieve point in the DM
8614 
8615   Output Parameters:
8616 + csize - The number of values in the closure, or PETSC_NULL
8617 - values - The array of values, which is a borrowed array and should not be freed
8618 
8619   Level: intermediate
8620 
8621 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8622 @*/
8623 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8624 {
8625   PetscScalar    *array, *vArray;
8626   PetscInt       *points = PETSC_NULL;
8627   PetscInt        offsets[32];
8628   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
8629   PetscErrorCode  ierr;
8630 
8631   PetscFunctionBegin;
8632   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8633   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8634   if (!section) {
8635     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8636   }
8637   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8638   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8639   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8640   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8641   /* Compress out points not in the section */
8642   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8643   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8644     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8645       points[q*2]   = points[p];
8646       points[q*2+1] = points[p+1];
8647       ++q;
8648     }
8649   }
8650   numPoints = q;
8651   for (p = 0, size = 0; p < numPoints*2; p += 2) {
8652     PetscInt dof, fdof;
8653 
8654     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8655     for (f = 0; f < numFields; ++f) {
8656       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8657       offsets[f+1] += fdof;
8658     }
8659     size += dof;
8660   }
8661   for (f = 1; f < numFields; ++f) {
8662     offsets[f+1] += offsets[f];
8663   }
8664   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
8665   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
8666   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
8667   for (p = 0; p < numPoints*2; p += 2) {
8668     PetscInt     o = points[p+1];
8669     PetscInt     dof, off, d;
8670     PetscScalar *varr;
8671 
8672     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8673     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
8674     varr = &vArray[off];
8675     if (numFields) {
8676       PetscInt fdof, foff, fcomp, f, c;
8677 
8678       for (f = 0, foff = 0; f < numFields; ++f) {
8679         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8680         if (o >= 0) {
8681           for (d = 0; d < fdof; ++d, ++offsets[f]) {
8682             array[offsets[f]] = varr[foff+d];
8683           }
8684         } else {
8685           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8686           for (d = fdof/fcomp-1; d >= 0; --d) {
8687             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
8688               array[offsets[f]] = varr[foff+d*fcomp+c];
8689             }
8690           }
8691         }
8692         foff += fdof;
8693       }
8694     } else {
8695       if (o >= 0) {
8696         for (d = 0; d < dof; ++d, ++offsets[0]) {
8697           array[offsets[0]] = varr[d];
8698         }
8699       } else {
8700         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
8701           array[offsets[0]] = varr[d];
8702         }
8703       }
8704     }
8705   }
8706   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8707   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
8708   if (csize) *csize = size;
8709   *values = array;
8710   PetscFunctionReturn(0);
8711 }
8712 
8713 #undef __FUNCT__
8714 #define __FUNCT__ "DMPlexVecRestoreClosure"
8715 /*@C
8716   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
8717 
8718   Not collective
8719 
8720   Input Parameters:
8721 + dm - The DM
8722 . section - The section describing the layout in v, or PETSC_NULL to use the default section
8723 . v - The local vector
8724 . point - The sieve point in the DM
8725 . csize - The number of values in the closure, or PETSC_NULL
8726 - values - The array of values, which is a borrowed array and should not be freed
8727 
8728   Level: intermediate
8729 
8730 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
8731 @*/
8732 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[])
8733 {
8734   PetscInt        size = 0;
8735   PetscErrorCode  ierr;
8736 
8737   PetscFunctionBegin;
8738   /* Should work without recalculating size */
8739   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
8740   PetscFunctionReturn(0);
8741 }
8742 
8743 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
8744 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
8745 
8746 #undef __FUNCT__
8747 #define __FUNCT__ "updatePoint_private"
8748 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8749 {
8750   PetscInt        cdof;  /* The number of constraints on this point */
8751   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8752   PetscScalar    *a;
8753   PetscInt        off, cind = 0, k;
8754   PetscErrorCode  ierr;
8755 
8756   PetscFunctionBegin;
8757   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
8758   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8759   a    = &array[off];
8760   if (!cdof || setBC) {
8761     if (orientation >= 0) {
8762       for (k = 0; k < dof; ++k) {
8763         fuse(&a[k], values[k]);
8764       }
8765     } else {
8766       for (k = 0; k < dof; ++k) {
8767         fuse(&a[k], values[dof-k-1]);
8768       }
8769     }
8770   } else {
8771     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
8772     if (orientation >= 0) {
8773       for (k = 0; k < dof; ++k) {
8774         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8775         fuse(&a[k], values[k]);
8776       }
8777     } else {
8778       for (k = 0; k < dof; ++k) {
8779         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
8780         fuse(&a[k], values[dof-k-1]);
8781       }
8782     }
8783   }
8784   PetscFunctionReturn(0);
8785 }
8786 
8787 #undef __FUNCT__
8788 #define __FUNCT__ "updatePointFields_private"
8789 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
8790 {
8791   PetscScalar   *a;
8792   PetscInt       numFields, off, foff, f;
8793   PetscErrorCode ierr;
8794 
8795   PetscFunctionBegin;
8796   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8797   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
8798   a    = &array[off];
8799   for (f = 0, foff = 0; f < numFields; ++f) {
8800     PetscInt        fdof, fcomp, fcdof;
8801     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
8802     PetscInt        cind = 0, k, c;
8803 
8804     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
8805     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
8806     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
8807     if (!fcdof || setBC) {
8808       if (orientation >= 0) {
8809         for (k = 0; k < fdof; ++k) {
8810           fuse(&a[foff+k], values[foffs[f]+k]);
8811         }
8812       } else {
8813         for (k = fdof/fcomp-1; k >= 0; --k) {
8814           for (c = 0; c < fcomp; ++c) {
8815             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8816           }
8817         }
8818       }
8819     } else {
8820       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
8821       if (orientation >= 0) {
8822         for (k = 0; k < fdof; ++k) {
8823           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
8824           fuse(&a[foff+k], values[foffs[f]+k]);
8825         }
8826       } else {
8827         for (k = fdof/fcomp-1; k >= 0; --k) {
8828           for (c = 0; c < fcomp; ++c) {
8829             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
8830             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
8831           }
8832         }
8833       }
8834     }
8835     foff     += fdof;
8836     foffs[f] += fdof;
8837   }
8838   PetscFunctionReturn(0);
8839 }
8840 
8841 #undef __FUNCT__
8842 #define __FUNCT__ "DMPlexVecSetClosure"
8843 /*@C
8844   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
8845 
8846   Not collective
8847 
8848   Input Parameters:
8849 + dm - The DM
8850 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
8851 . v - The local vector
8852 . point - The sieve point in the DM
8853 . values - The array of values, which is a borrowed array and should not be freed
8854 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
8855 
8856   Level: intermediate
8857 
8858 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
8859 @*/
8860 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode)
8861 {
8862   PetscScalar    *array;
8863   PetscInt       *points = PETSC_NULL;
8864   PetscInt        offsets[32];
8865   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
8866   PetscErrorCode  ierr;
8867 
8868   PetscFunctionBegin;
8869   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8870   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
8871   if (!section) {
8872     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
8873   }
8874   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
8875   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
8876   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
8877   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8878   /* Compress out points not in the section */
8879   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8880   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8881     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8882       points[q*2]   = points[p];
8883       points[q*2+1] = points[p+1];
8884       ++q;
8885     }
8886   }
8887   numPoints = q;
8888   for (p = 0; p < numPoints*2; p += 2) {
8889     PetscInt fdof;
8890 
8891     for (f = 0; f < numFields; ++f) {
8892       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8893       offsets[f+1] += fdof;
8894     }
8895   }
8896   for (f = 1; f < numFields; ++f) {
8897     offsets[f+1] += offsets[f];
8898   }
8899   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
8900   if (numFields) {
8901     switch (mode) {
8902     case INSERT_VALUES:
8903       for (p = 0; p < numPoints*2; p += 2) {
8904         PetscInt o = points[p+1];
8905         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
8906       } break;
8907     case INSERT_ALL_VALUES:
8908       for (p = 0; p < numPoints*2; p += 2) {
8909         PetscInt o = points[p+1];
8910         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
8911       } break;
8912     case ADD_VALUES:
8913       for (p = 0; p < numPoints*2; p += 2) {
8914         PetscInt o = points[p+1];
8915         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
8916       } break;
8917     case ADD_ALL_VALUES:
8918       for (p = 0; p < numPoints*2; p += 2) {
8919         PetscInt o = points[p+1];
8920         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
8921       } break;
8922     default:
8923       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8924     }
8925   } else {
8926     switch (mode) {
8927     case INSERT_VALUES:
8928       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8929         PetscInt o = points[p+1];
8930         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8931         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
8932       } break;
8933     case INSERT_ALL_VALUES:
8934       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8935         PetscInt o = points[p+1];
8936         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8937         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
8938       } break;
8939     case ADD_VALUES:
8940       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8941         PetscInt o = points[p+1];
8942         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8943         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
8944       } break;
8945     case ADD_ALL_VALUES:
8946       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8947         PetscInt o = points[p+1];
8948         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8949         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
8950       } break;
8951     default:
8952       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
8953     }
8954   }
8955   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8956   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
8957   PetscFunctionReturn(0);
8958 }
8959 
8960 #undef __FUNCT__
8961 #define __FUNCT__ "DMPlexPrintMatSetValues"
8962 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
8963 {
8964   PetscMPIInt    rank;
8965   PetscInt       i, j;
8966   PetscErrorCode ierr;
8967 
8968   PetscFunctionBegin;
8969   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
8970   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
8971   for (i = 0; i < numIndices; i++) {
8972     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
8973   }
8974   for (i = 0; i < numIndices; i++) {
8975     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
8976     for (j = 0; j < numIndices; j++) {
8977 #if defined(PETSC_USE_COMPLEX)
8978       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
8979 #else
8980       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
8981 #endif
8982     }
8983     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
8984   }
8985   PetscFunctionReturn(0);
8986 }
8987 
8988 #undef __FUNCT__
8989 #define __FUNCT__ "indicesPoint_private"
8990 /* . off - The global offset of this point */
8991 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[])
8992 {
8993   PetscInt        cdof;  /* The number of constraints on this point */
8994   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
8995   PetscInt        cind = 0, k;
8996   PetscErrorCode  ierr;
8997 
8998   PetscFunctionBegin;
8999   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
9000   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
9001   if (!cdof || setBC) {
9002     if (orientation >= 0) {
9003       for (k = 0; k < dof; ++k) {
9004         indices[k] = off+k;
9005       }
9006     } else {
9007       for (k = 0; k < dof; ++k) {
9008         indices[dof-k-1] = off+k;
9009       }
9010     }
9011   } else {
9012     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
9013     if (orientation >= 0) {
9014       for (k = 0; k < dof; ++k) {
9015         if ((cind < cdof) && (k == cdofs[cind])) {
9016           /* Insert check for returning constrained indices */
9017           indices[k] = -(off+k+1);
9018           ++cind;
9019         } else {
9020           indices[k] = off+k-cind;
9021         }
9022       }
9023     } else {
9024       for (k = 0; k < dof; ++k) {
9025         if ((cind < cdof) && (k == cdofs[cind])) {
9026           /* Insert check for returning constrained indices */
9027           indices[dof-k-1] = -(off+k+1);
9028           ++cind;
9029         } else {
9030           indices[dof-k-1] = off+k-cind;
9031         }
9032       }
9033     }
9034   }
9035   PetscFunctionReturn(0);
9036 }
9037 
9038 #undef __FUNCT__
9039 #define __FUNCT__ "indicesPointFields_private"
9040 /* . off - The global offset of this point */
9041 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[])
9042 {
9043   PetscInt       numFields, foff, f;
9044   PetscErrorCode ierr;
9045 
9046   PetscFunctionBegin;
9047   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9048   for (f = 0, foff = 0; f < numFields; ++f) {
9049     PetscInt        fdof, fcomp, cfdof;
9050     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
9051     PetscInt        cind = 0, k, c;
9052 
9053     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
9054     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
9055     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
9056     if (!cfdof || setBC) {
9057       if (orientation >= 0) {
9058         for (k = 0; k < fdof; ++k) {
9059           indices[foffs[f]+k] = off+foff+k;
9060         }
9061       } else {
9062         for (k = fdof/fcomp-1; k >= 0; --k) {
9063           for (c = 0; c < fcomp; ++c) {
9064             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
9065           }
9066         }
9067       }
9068     } else {
9069       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
9070       if (orientation >= 0) {
9071         for (k = 0; k < fdof; ++k) {
9072           if ((cind < cfdof) && (k == fcdofs[cind])) {
9073             indices[foffs[f]+k] = -(off+foff+k+1);
9074             ++cind;
9075           } else {
9076             indices[foffs[f]+k] = off+foff+k-cind;
9077           }
9078         }
9079       } else {
9080         for (k = fdof/fcomp-1; k >= 0; --k) {
9081           for (c = 0; c < fcomp; ++c) {
9082             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
9083               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
9084               ++cind;
9085             } else {
9086               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
9087             }
9088           }
9089         }
9090       }
9091     }
9092     foff     += fdof - cfdof;
9093     foffs[f] += fdof;
9094   }
9095   PetscFunctionReturn(0);
9096 }
9097 
9098 #undef __FUNCT__
9099 #define __FUNCT__ "DMPlexMatSetClosure"
9100 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
9101 {
9102   DM_Plex     *mesh   = (DM_Plex *) dm->data;
9103   PetscInt       *points = PETSC_NULL;
9104   PetscInt       *indices;
9105   PetscInt        offsets[32];
9106   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
9107   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
9108   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
9109   PetscErrorCode  ierr;
9110 
9111   PetscFunctionBegin;
9112   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9113   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
9114   if (useDefault) {
9115     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9116   }
9117   if (useGlobalDefault) {
9118     if (useDefault) {
9119       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
9120     } else {
9121       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9122     }
9123   }
9124   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9125   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
9126   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
9127   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9128   /* Compress out points not in the section */
9129   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
9130   for (p = 0, q = 0; p < numPoints*2; p += 2) {
9131     if ((points[p] >= pStart) && (points[p] < pEnd)) {
9132       points[q*2]   = points[p];
9133       points[q*2+1] = points[p+1];
9134       ++q;
9135     }
9136   }
9137   numPoints = q;
9138   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
9139     PetscInt fdof;
9140 
9141     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
9142     for (f = 0; f < numFields; ++f) {
9143       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
9144       offsets[f+1] += fdof;
9145     }
9146     numIndices += dof;
9147   }
9148   for (f = 1; f < numFields; ++f) {
9149     offsets[f+1] += offsets[f];
9150   }
9151   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
9152   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9153   if (numFields) {
9154     for (p = 0; p < numPoints*2; p += 2) {
9155       PetscInt o = points[p+1];
9156       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9157       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
9158     }
9159   } else {
9160     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
9161       PetscInt o = points[p+1];
9162       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
9163       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
9164     }
9165   }
9166   if (useGlobalDefault && !useDefault) {
9167     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9168   }
9169   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
9170   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
9171   if (ierr) {
9172     PetscMPIInt    rank;
9173     PetscErrorCode ierr2;
9174 
9175     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
9176     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
9177     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
9178     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
9179     CHKERRQ(ierr);
9180   }
9181   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
9182   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
9183   PetscFunctionReturn(0);
9184 }
9185 
9186 #undef __FUNCT__
9187 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
9188 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9189 {
9190   PetscSection       coordSection;
9191   Vec                coordinates;
9192   const PetscScalar *coords;
9193   const PetscInt     dim = 2;
9194   PetscInt           d, f;
9195   PetscErrorCode     ierr;
9196 
9197   PetscFunctionBegin;
9198   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9199   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9200   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9201   if (v0) {
9202     for (d = 0; d < dim; d++) {
9203       v0[d] = PetscRealPart(coords[d]);
9204     }
9205   }
9206   if (J) {
9207     for (d = 0; d < dim; d++) {
9208       for (f = 0; f < dim; f++) {
9209         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9210       }
9211     }
9212     *detJ = J[0]*J[3] - J[1]*J[2];
9213 #if 0
9214     if (detJ < 0.0) {
9215       const PetscReal xLength = mesh->periodicity[0];
9216 
9217       if (xLength != 0.0) {
9218         PetscReal v0x = coords[0*dim+0];
9219 
9220         if (v0x == 0.0) {
9221           v0x = v0[0] = xLength;
9222         }
9223         for (f = 0; f < dim; f++) {
9224           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
9225 
9226           J[0*dim+f] = 0.5*(px - v0x);
9227         }
9228       }
9229       detJ = J[0]*J[3] - J[1]*J[2];
9230     }
9231 #endif
9232     PetscLogFlops(8.0 + 3.0);
9233   }
9234   if (invJ) {
9235     const PetscReal invDet = 1.0/(*detJ);
9236 
9237     invJ[0] =  invDet*J[3];
9238     invJ[1] = -invDet*J[1];
9239     invJ[2] = -invDet*J[2];
9240     invJ[3] =  invDet*J[0];
9241     PetscLogFlops(5.0);
9242   }
9243   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9244   PetscFunctionReturn(0);
9245 }
9246 
9247 #undef __FUNCT__
9248 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
9249 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9250 {
9251   PetscSection       coordSection;
9252   Vec                coordinates;
9253   const PetscScalar *coords;
9254   const PetscInt     dim = 2;
9255   PetscInt           d, f;
9256   PetscErrorCode     ierr;
9257 
9258   PetscFunctionBegin;
9259   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9260   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9261   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9262   if (v0) {
9263     for (d = 0; d < dim; d++) {
9264       v0[d] = PetscRealPart(coords[d]);
9265     }
9266   }
9267   if (J) {
9268     for (d = 0; d < dim; d++) {
9269       for (f = 0; f < dim; f++) {
9270         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9271       }
9272     }
9273     *detJ = J[0]*J[3] - J[1]*J[2];
9274     PetscLogFlops(8.0 + 3.0);
9275   }
9276   if (invJ) {
9277     const PetscReal invDet = 1.0/(*detJ);
9278 
9279     invJ[0] =  invDet*J[3];
9280     invJ[1] = -invDet*J[1];
9281     invJ[2] = -invDet*J[2];
9282     invJ[3] =  invDet*J[0];
9283     PetscLogFlops(5.0);
9284   }
9285   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9286   PetscFunctionReturn(0);
9287 }
9288 
9289 #undef __FUNCT__
9290 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
9291 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9292 {
9293   PetscSection       coordSection;
9294   Vec                coordinates;
9295   const PetscScalar *coords;
9296   const PetscInt     dim = 3;
9297   PetscInt           d, f;
9298   PetscErrorCode     ierr;
9299 
9300   PetscFunctionBegin;
9301   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9302   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9303   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9304   if (v0) {
9305     for (d = 0; d < dim; d++) {
9306       v0[d] = PetscRealPart(coords[d]);
9307     }
9308   }
9309   if (J) {
9310     for (d = 0; d < dim; d++) {
9311       for (f = 0; f < dim; f++) {
9312         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9313       }
9314     }
9315     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
9316     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9317              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9318              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9319     PetscLogFlops(18.0 + 12.0);
9320   }
9321   if (invJ) {
9322     const PetscReal invDet = 1.0/(*detJ);
9323 
9324     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9325     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9326     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9327     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9328     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9329     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9330     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9331     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9332     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9333     PetscLogFlops(37.0);
9334   }
9335   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9336   PetscFunctionReturn(0);
9337 }
9338 
9339 #undef __FUNCT__
9340 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
9341 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
9342 {
9343   PetscSection       coordSection;
9344   Vec                coordinates;
9345   const PetscScalar *coords;
9346   const PetscInt     dim = 3;
9347   PetscInt           d;
9348   PetscErrorCode     ierr;
9349 
9350   PetscFunctionBegin;
9351   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9352   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9353   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9354   if (v0) {
9355     for (d = 0; d < dim; d++) {
9356       v0[d] = PetscRealPart(coords[d]);
9357     }
9358   }
9359   if (J) {
9360     for (d = 0; d < dim; d++) {
9361       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9362       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9363       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
9364     }
9365     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
9366              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
9367              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
9368     PetscLogFlops(18.0 + 12.0);
9369   }
9370   if (invJ) {
9371     const PetscReal invDet = -1.0/(*detJ);
9372 
9373     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
9374     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
9375     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
9376     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
9377     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
9378     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
9379     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
9380     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
9381     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
9382     PetscLogFlops(37.0);
9383   }
9384   *detJ *= 8.0;
9385   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
9386   PetscFunctionReturn(0);
9387 }
9388 
9389 #undef __FUNCT__
9390 #define __FUNCT__ "DMPlexComputeCellGeometry"
9391 /*@C
9392   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
9393 
9394   Collective on DM
9395 
9396   Input Arguments:
9397 + dm   - the DM
9398 - cell - the cell
9399 
9400   Output Arguments:
9401 + v0   - the translation part of this affine transform
9402 . J    - the Jacobian of the transform to the reference element
9403 . invJ - the inverse of the Jacobian
9404 - detJ - the Jacobian determinant
9405 
9406   Level: advanced
9407 
9408 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
9409 @*/
9410 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ)
9411 {
9412   PetscInt       dim, coneSize;
9413   PetscErrorCode ierr;
9414 
9415   PetscFunctionBegin;
9416   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9417   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9418   switch (dim) {
9419   case 2:
9420     switch (coneSize) {
9421     case 3:
9422       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9423       break;
9424     case 4:
9425       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9426       break;
9427     default:
9428       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9429     }
9430     break;
9431   case 3:
9432     switch (coneSize) {
9433     case 4:
9434       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9435       break;
9436     case 8:
9437       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
9438       break;
9439     default:
9440       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of vertices %D in cell %D for element geometry computation", coneSize, cell);
9441     }
9442     break;
9443   default:
9444     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
9445   }
9446   PetscFunctionReturn(0);
9447 }
9448 
9449 #undef __FUNCT__
9450 #define __FUNCT__ "DMPlexGetFaceOrientation"
9451 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9452 {
9453   MPI_Comm       comm      = ((PetscObject) dm)->comm;
9454   PetscBool      posOrient = PETSC_FALSE;
9455   const PetscInt debug     = 0;
9456   PetscInt       cellDim, faceSize, f;
9457   PetscErrorCode ierr;
9458 
9459   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
9460   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
9461 
9462   if (cellDim == numCorners-1) {
9463     /* Simplices */
9464     faceSize  = numCorners-1;
9465     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
9466   } else if (cellDim == 1 && numCorners == 3) {
9467     /* Quadratic line */
9468     faceSize  = 1;
9469     posOrient = PETSC_TRUE;
9470   } else if (cellDim == 2 && numCorners == 4) {
9471     /* Quads */
9472     faceSize  = 2;
9473     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
9474       posOrient = PETSC_TRUE;
9475     } else if ((indices[0] == 3) && (indices[1] == 0)) {
9476       posOrient = PETSC_TRUE;
9477     } else {
9478       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
9479         posOrient = PETSC_FALSE;
9480       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
9481     }
9482   } else if (cellDim == 2 && numCorners == 6) {
9483     /* Quadratic triangle (I hate this) */
9484     /* Edges are determined by the first 2 vertices (corners of edges) */
9485     const PetscInt faceSizeTri = 3;
9486     PetscInt  sortedIndices[3], i, iFace;
9487     PetscBool found = PETSC_FALSE;
9488     PetscInt  faceVerticesTriSorted[9] = {
9489       0, 3,  4, /* bottom */
9490       1, 4,  5, /* right */
9491       2, 3,  5, /* left */
9492     };
9493     PetscInt  faceVerticesTri[9] = {
9494       0, 3,  4, /* bottom */
9495       1, 4,  5, /* right */
9496       2, 5,  3, /* left */
9497     };
9498 
9499     faceSize = faceSizeTri;
9500     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
9501     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
9502     for (iFace = 0; iFace < 3; ++iFace) {
9503       const PetscInt ii = iFace*faceSizeTri;
9504       PetscInt       fVertex, cVertex;
9505 
9506       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
9507           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
9508         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
9509           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
9510             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
9511               faceVertices[fVertex] = origVertices[cVertex];
9512               break;
9513             }
9514           }
9515         }
9516         found = PETSC_TRUE;
9517         break;
9518       }
9519     }
9520     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
9521     if (posOriented) {*posOriented = PETSC_TRUE;}
9522     PetscFunctionReturn(0);
9523   } else if (cellDim == 2 && numCorners == 9) {
9524     /* Quadratic quad (I hate this) */
9525     /* Edges are determined by the first 2 vertices (corners of edges) */
9526     const PetscInt faceSizeQuad = 3;
9527     PetscInt  sortedIndices[3], i, iFace;
9528     PetscBool found = PETSC_FALSE;
9529     PetscInt  faceVerticesQuadSorted[12] = {
9530       0, 1,  4, /* bottom */
9531       1, 2,  5, /* right */
9532       2, 3,  6, /* top */
9533       0, 3,  7, /* left */
9534     };
9535     PetscInt  faceVerticesQuad[12] = {
9536       0, 1,  4, /* bottom */
9537       1, 2,  5, /* right */
9538       2, 3,  6, /* top */
9539       3, 0,  7, /* left */
9540     };
9541 
9542     faceSize = faceSizeQuad;
9543     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
9544     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
9545     for (iFace = 0; iFace < 4; ++iFace) {
9546       const PetscInt ii = iFace*faceSizeQuad;
9547       PetscInt       fVertex, cVertex;
9548 
9549       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
9550           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
9551         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
9552           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
9553             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
9554               faceVertices[fVertex] = origVertices[cVertex];
9555               break;
9556             }
9557           }
9558         }
9559         found = PETSC_TRUE;
9560         break;
9561       }
9562     }
9563     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
9564     if (posOriented) {*posOriented = PETSC_TRUE;}
9565     PetscFunctionReturn(0);
9566   } else if (cellDim == 3 && numCorners == 8) {
9567     /* Hexes
9568        A hex is two oriented quads with the normal of the first
9569        pointing up at the second.
9570 
9571           7---6
9572          /|  /|
9573         4---5 |
9574         | 3-|-2
9575         |/  |/
9576         0---1
9577 
9578         Faces are determined by the first 4 vertices (corners of faces) */
9579     const PetscInt faceSizeHex = 4;
9580     PetscInt  sortedIndices[4], i, iFace;
9581     PetscBool found = PETSC_FALSE;
9582     PetscInt faceVerticesHexSorted[24] = {
9583       0, 1, 2, 3,  /* bottom */
9584       4, 5, 6, 7,  /* top */
9585       0, 1, 4, 5,  /* front */
9586       1, 2, 5, 6,  /* right */
9587       2, 3, 6, 7,  /* back */
9588       0, 3, 4, 7,  /* left */
9589     };
9590     PetscInt faceVerticesHex[24] = {
9591       3, 2, 1, 0,  /* bottom */
9592       4, 5, 6, 7,  /* top */
9593       0, 1, 5, 4,  /* front */
9594       1, 2, 6, 5,  /* right */
9595       2, 3, 7, 6,  /* back */
9596       3, 0, 4, 7,  /* left */
9597     };
9598 
9599     faceSize = faceSizeHex;
9600     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
9601     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
9602     for (iFace = 0; iFace < 6; ++iFace) {
9603       const PetscInt ii = iFace*faceSizeHex;
9604       PetscInt       fVertex, cVertex;
9605 
9606       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
9607           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
9608           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
9609           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
9610         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
9611           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
9612             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
9613               faceVertices[fVertex] = origVertices[cVertex];
9614               break;
9615             }
9616           }
9617         }
9618         found = PETSC_TRUE;
9619         break;
9620       }
9621     }
9622     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9623     if (posOriented) {*posOriented = PETSC_TRUE;}
9624     PetscFunctionReturn(0);
9625   } else if (cellDim == 3 && numCorners == 10) {
9626     /* Quadratic tet */
9627     /* Faces are determined by the first 3 vertices (corners of faces) */
9628     const PetscInt faceSizeTet = 6;
9629     PetscInt  sortedIndices[6], i, iFace;
9630     PetscBool found = PETSC_FALSE;
9631     PetscInt faceVerticesTetSorted[24] = {
9632       0, 1, 2,  6, 7, 8, /* bottom */
9633       0, 3, 4,  6, 7, 9,  /* front */
9634       1, 4, 5,  7, 8, 9,  /* right */
9635       2, 3, 5,  6, 8, 9,  /* left */
9636     };
9637     PetscInt faceVerticesTet[24] = {
9638       0, 1, 2,  6, 7, 8, /* bottom */
9639       0, 4, 3,  6, 7, 9,  /* front */
9640       1, 5, 4,  7, 8, 9,  /* right */
9641       2, 3, 5,  8, 6, 9,  /* left */
9642     };
9643 
9644     faceSize = faceSizeTet;
9645     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
9646     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
9647     for (iFace=0; iFace < 4; ++iFace) {
9648       const PetscInt ii = iFace*faceSizeTet;
9649       PetscInt       fVertex, cVertex;
9650 
9651       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
9652           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
9653           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
9654           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
9655         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
9656           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
9657             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
9658               faceVertices[fVertex] = origVertices[cVertex];
9659               break;
9660             }
9661           }
9662         }
9663         found = PETSC_TRUE;
9664         break;
9665       }
9666     }
9667     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
9668     if (posOriented) {*posOriented = PETSC_TRUE;}
9669     PetscFunctionReturn(0);
9670   } else if (cellDim == 3 && numCorners == 27) {
9671     /* Quadratic hexes (I hate this)
9672        A hex is two oriented quads with the normal of the first
9673        pointing up at the second.
9674 
9675          7---6
9676         /|  /|
9677        4---5 |
9678        | 3-|-2
9679        |/  |/
9680        0---1
9681 
9682        Faces are determined by the first 4 vertices (corners of faces) */
9683     const PetscInt faceSizeQuadHex = 9;
9684     PetscInt  sortedIndices[9], i, iFace;
9685     PetscBool found = PETSC_FALSE;
9686     PetscInt faceVerticesQuadHexSorted[54] = {
9687       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
9688       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9689       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
9690       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
9691       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
9692       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
9693     };
9694     PetscInt faceVerticesQuadHex[54] = {
9695       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
9696       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
9697       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
9698       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
9699       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
9700       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
9701     };
9702 
9703     faceSize = faceSizeQuadHex;
9704     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
9705     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
9706     for (iFace = 0; iFace < 6; ++iFace) {
9707       const PetscInt ii = iFace*faceSizeQuadHex;
9708       PetscInt       fVertex, cVertex;
9709 
9710       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
9711           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
9712           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
9713           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
9714         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
9715           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
9716             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
9717               faceVertices[fVertex] = origVertices[cVertex];
9718               break;
9719             }
9720           }
9721         }
9722         found = PETSC_TRUE;
9723         break;
9724       }
9725     }
9726     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
9727     if (posOriented) {*posOriented = PETSC_TRUE;}
9728     PetscFunctionReturn(0);
9729   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
9730   if (!posOrient) {
9731     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
9732     for (f = 0; f < faceSize; ++f) {
9733       faceVertices[f] = origVertices[faceSize-1 - f];
9734     }
9735   } else {
9736     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
9737     for (f = 0; f < faceSize; ++f) {
9738       faceVertices[f] = origVertices[f];
9739     }
9740   }
9741   if (posOriented) {*posOriented = posOrient;}
9742   PetscFunctionReturn(0);
9743 }
9744 
9745 #undef __FUNCT__
9746 #define __FUNCT__ "DMPlexGetOrientedFace"
9747 /*
9748     Given a cell and a face, as a set of vertices,
9749       return the oriented face, as a set of vertices, in faceVertices
9750     The orientation is such that the face normal points out of the cell
9751 */
9752 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
9753 {
9754   const PetscInt *cone = PETSC_NULL;
9755   PetscInt        coneSize, v, f, v2;
9756   PetscInt        oppositeVertex = -1;
9757   PetscErrorCode  ierr;
9758 
9759   PetscFunctionBegin;
9760   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
9761   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
9762   for (v = 0, v2 = 0; v < coneSize; ++v) {
9763     PetscBool found  = PETSC_FALSE;
9764 
9765     for (f = 0; f < faceSize; ++f) {
9766       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
9767     }
9768     if (found) {
9769       indices[v2]      = v;
9770       origVertices[v2] = cone[v];
9771       ++v2;
9772     } else {
9773       oppositeVertex = v;
9774     }
9775   }
9776   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
9777   PetscFunctionReturn(0);
9778 }
9779 
9780 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
9781 {
9782   switch (i) {
9783   case 0:
9784     switch (j) {
9785     case 0: return 0;
9786     case 1:
9787       switch (k) {
9788       case 0: return 0;
9789       case 1: return 0;
9790       case 2: return 1;
9791       }
9792     case 2:
9793       switch (k) {
9794       case 0: return 0;
9795       case 1: return -1;
9796       case 2: return 0;
9797       }
9798     }
9799   case 1:
9800     switch (j) {
9801     case 0:
9802       switch (k) {
9803       case 0: return 0;
9804       case 1: return 0;
9805       case 2: return -1;
9806       }
9807     case 1: return 0;
9808     case 2:
9809       switch (k) {
9810       case 0: return 1;
9811       case 1: return 0;
9812       case 2: return 0;
9813       }
9814     }
9815   case 2:
9816     switch (j) {
9817     case 0:
9818       switch (k) {
9819       case 0: return 0;
9820       case 1: return 1;
9821       case 2: return 0;
9822       }
9823     case 1:
9824       switch (k) {
9825       case 0: return -1;
9826       case 1: return 0;
9827       case 2: return 0;
9828       }
9829     case 2: return 0;
9830     }
9831   }
9832   return 0;
9833 }
9834 
9835 #undef __FUNCT__
9836 #define __FUNCT__ "DMPlexCreateRigidBody"
9837 /*@C
9838   DMPlexCreateRigidBody - create rigid body modes from coordinates
9839 
9840   Collective on DM
9841 
9842   Input Arguments:
9843 + dm - the DM
9844 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
9845 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
9846 
9847   Output Argument:
9848 . sp - the null space
9849 
9850   Note: This is necessary to take account of Dirichlet conditions on the displacements
9851 
9852   Level: advanced
9853 
9854 .seealso: MatNullSpaceCreate()
9855 @*/
9856 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
9857 {
9858   MPI_Comm       comm = ((PetscObject) dm)->comm;
9859   Vec            coordinates, localMode, mode[6];
9860   PetscSection   coordSection;
9861   PetscScalar   *coords;
9862   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
9863   PetscErrorCode ierr;
9864 
9865   PetscFunctionBegin;
9866   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9867   if (dim == 1) {
9868     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
9869     PetscFunctionReturn(0);
9870   }
9871   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
9872   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
9873   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
9874   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9875   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9876   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9877   m    = (dim*(dim+1))/2;
9878   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
9879   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
9880   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
9881   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
9882   /* Assume P1 */
9883   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
9884   for (d = 0; d < dim; ++d) {
9885     PetscScalar values[3] = {0.0, 0.0, 0.0};
9886 
9887     values[d] = 1.0;
9888     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9889     for (v = vStart; v < vEnd; ++v) {
9890       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9891     }
9892     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9893     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9894   }
9895   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
9896   for (d = dim; d < dim*(dim+1)/2; ++d) {
9897     PetscInt i, j, k = dim > 2 ? d - dim : d;
9898 
9899     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
9900     for (v = vStart; v < vEnd; ++v) {
9901       PetscScalar values[3] = {0.0, 0.0, 0.0};
9902       PetscInt    off;
9903 
9904       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
9905       for (i = 0; i < dim; ++i) {
9906         for (j = 0; j < dim; ++j) {
9907           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
9908         }
9909       }
9910       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
9911     }
9912     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9913     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
9914   }
9915   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
9916   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
9917   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
9918   /* Orthonormalize system */
9919   for (i = dim; i < m; ++i) {
9920     PetscScalar dots[6];
9921 
9922     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
9923     for (j = 0; j < i; ++j) dots[j] *= -1.0;
9924     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
9925     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
9926   }
9927   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
9928   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
9929   PetscFunctionReturn(0);
9930 }
9931 
9932 #undef __FUNCT__
9933 #define __FUNCT__ "DMPlexGetHybridBounds"
9934 PetscErrorCode DMPlexGetHybridBounds(DM dm, PetscInt *cMax, PetscInt *fMax, PetscInt *eMax, PetscInt *vMax)
9935 {
9936   DM_Plex       *mesh = (DM_Plex *) dm->data;
9937   PetscInt       dim;
9938   PetscErrorCode ierr;
9939 
9940   PetscFunctionBegin;
9941   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9942   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9943   if (cMax) *cMax = mesh->hybridPointMax[dim];
9944   if (fMax) *fMax = mesh->hybridPointMax[dim-1];
9945   if (eMax) *eMax = mesh->hybridPointMax[1];
9946   if (vMax) *vMax = mesh->hybridPointMax[0];
9947   PetscFunctionReturn(0);
9948 }
9949 
9950 #undef __FUNCT__
9951 #define __FUNCT__ "DMPlexSetHybridBounds"
9952 PetscErrorCode DMPlexSetHybridBounds(DM dm, PetscInt cMax, PetscInt fMax, PetscInt eMax, PetscInt vMax)
9953 {
9954   DM_Plex       *mesh = (DM_Plex *) dm->data;
9955   PetscInt       dim;
9956   PetscErrorCode ierr;
9957 
9958   PetscFunctionBegin;
9959   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9960   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9961   if (cMax >= 0) mesh->hybridPointMax[dim]   = cMax;
9962   if (fMax >= 0) mesh->hybridPointMax[dim-1] = fMax;
9963   if (eMax >= 0) mesh->hybridPointMax[1]     = eMax;
9964   if (vMax >= 0) mesh->hybridPointMax[0]     = vMax;
9965   PetscFunctionReturn(0);
9966 }
9967 
9968 #undef __FUNCT__
9969 #define __FUNCT__ "DMPlexGetVTKCellHeight"
9970 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
9971 {
9972   DM_Plex *mesh = (DM_Plex *) dm->data;
9973 
9974   PetscFunctionBegin;
9975   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9976   PetscValidPointer(cellHeight, 2);
9977   *cellHeight = mesh->vtkCellHeight;
9978   PetscFunctionReturn(0);
9979 }
9980 
9981 #undef __FUNCT__
9982 #define __FUNCT__ "DMPlexSetVTKCellHeight"
9983 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
9984 {
9985   DM_Plex *mesh = (DM_Plex *) dm->data;
9986 
9987   PetscFunctionBegin;
9988   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9989   mesh->vtkCellHeight = cellHeight;
9990   PetscFunctionReturn(0);
9991 }
9992 
9993 #undef __FUNCT__
9994 #define __FUNCT__ "DMPlexInsertFace_Private"
9995 /*
9996   DMPlexInsertFace_Private - Puts a face into the mesh
9997 
9998   Not collective
9999 
10000   Input Parameters:
10001   + dm              - The DMPlex
10002   . numFaceVertex   - The number of vertices in the face
10003   . faceVertices    - The vertices in the face for dm
10004   . subfaceVertices - The vertices in the face for subdm
10005   . numCorners      - The number of vertices in the cell
10006   . cell            - A cell in dm containing the face
10007   . subcell         - A cell in subdm containing the face
10008   . firstFace       - First face in the mesh
10009   - newFacePoint    - Next face in the mesh
10010 
10011   Output Parameters:
10012   . newFacePoint - Contains next face point number on input, updated on output
10013 
10014   Level: developer
10015 */
10016 PetscErrorCode DMPlexInsertFace_Private(DM dm, DM subdm, PetscInt numFaceVertices, const PetscInt faceVertices[], const PetscInt subfaceVertices[], PetscInt numCorners, PetscInt cell, PetscInt subcell, PetscInt firstFace, PetscInt *newFacePoint)
10017 {
10018   MPI_Comm        comm    = ((PetscObject) dm)->comm;
10019   DM_Plex     *submesh = (DM_Plex *) subdm->data;
10020   const PetscInt *faces;
10021   PetscInt        numFaces, coneSize;
10022   PetscErrorCode  ierr;
10023 
10024   PetscFunctionBegin;
10025   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
10026   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
10027 #if 0
10028   /* Cannot use this because support() has not been constructed yet */
10029   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10030 #else
10031   {
10032     PetscInt f;
10033 
10034     numFaces = 0;
10035     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
10036     for (f = firstFace; f < *newFacePoint; ++f) {
10037       PetscInt dof, off, d;
10038 
10039       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
10040       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
10041       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
10042       for (d = 0; d < dof; ++d) {
10043         const PetscInt p = submesh->cones[off+d];
10044         PetscInt       v;
10045 
10046         for (v = 0; v < numFaceVertices; ++v) {
10047           if (subfaceVertices[v] == p) break;
10048         }
10049         if (v == numFaceVertices) break;
10050       }
10051       if (d == dof) {
10052         numFaces = 1;
10053         ((PetscInt *) faces)[0] = f;
10054       }
10055     }
10056   }
10057 #endif
10058   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
10059   else if (numFaces == 1) {
10060     /* Add the other cell neighbor for this face */
10061     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
10062   } else {
10063     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
10064     PetscBool posOriented;
10065 
10066     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10067     origVertices = &orientedVertices[numFaceVertices];
10068     indices      = &orientedVertices[numFaceVertices*2];
10069     orientedSubVertices = &orientedVertices[numFaceVertices*3];
10070     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
10071     /* TODO: I know that routine should return a permutation, not the indices */
10072     for (v = 0; v < numFaceVertices; ++v) {
10073       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
10074       for (ov = 0; ov < numFaceVertices; ++ov) {
10075         if (orientedVertices[ov] == vertex) {
10076           orientedSubVertices[ov] = subvertex;
10077           break;
10078         }
10079       }
10080       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
10081     }
10082     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
10083     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
10084     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
10085     ++(*newFacePoint);
10086   }
10087   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
10088   PetscFunctionReturn(0);
10089 }
10090 
10091 #undef __FUNCT__
10092 #define __FUNCT__ "DMPlexCreateSubmesh"
10093 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
10094 {
10095   MPI_Comm        comm = ((PetscObject) dm)->comm;
10096   DM_Plex     *submesh;
10097   PetscBool       boundaryFaces = PETSC_FALSE;
10098   PetscSection    coordSection, subCoordSection;
10099   Vec             coordinates, subCoordinates;
10100   PetscScalar    *coords, *subCoords;
10101   IS              labelIS;
10102   const PetscInt *subVertices;
10103   PetscInt       *subVerticesActive, *tmpPoints;
10104   PetscInt       *subCells = PETSC_NULL;
10105   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
10106   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
10107   PetscInt        dim; /* Right now, do not specify dimension */
10108   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
10109   PetscErrorCode  ierr;
10110 
10111   PetscFunctionBegin;
10112   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10113   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10114   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10115   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
10116   ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10117   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10118   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10119   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10120   subface = &face[maxConeSize];
10121   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
10122   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
10123   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
10124   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
10125   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
10126   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
10127   maxSubCells = numSubVertices;
10128   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
10129   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
10130   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
10131   for (v = 0; v < numSubVertices; ++v) {
10132     const PetscInt vertex = subVertices[v];
10133     PetscInt *star = PETSC_NULL;
10134     PetscInt  starSize, numCells = 0;
10135 
10136     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10137     for (p = 0; p < starSize*2; p += 2) {
10138       const PetscInt point = star[p];
10139       if ((point >= cStart) && (point < cEnd)) {
10140         star[numCells++] = point;
10141       }
10142     }
10143     numOldSubCells = numSubCells;
10144     for (c = 0; c < numCells; ++c) {
10145       const PetscInt cell    = star[c];
10146       PetscInt      *closure = PETSC_NULL;
10147       PetscInt       closureSize, numCorners = 0, faceSize = 0;
10148       PetscInt       cellLoc;
10149 
10150       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
10151       if (cellLoc >= 0) continue;
10152       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10153       for (p = 0; p < closureSize*2; p += 2) {
10154         const PetscInt point = closure[p];
10155         if ((point >= vStart) && (point < vEnd)) {
10156           closure[numCorners++] = point;
10157         }
10158       }
10159       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
10160       for (corner = 0; corner < numCorners; ++corner) {
10161         const PetscInt cellVertex = closure[corner];
10162         PetscInt       subVertex;
10163 
10164         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
10165         if (subVertex >= 0) { /* contains submesh vertex */
10166           for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10167           if (i == faceSize) {
10168             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
10169             face[faceSize]    = cellVertex;
10170             subface[faceSize] = subVertex;
10171             ++faceSize;
10172           }
10173         }
10174       }
10175       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10176       if (faceSize >= nFV) {
10177         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10178         if (numSubCells >= maxSubCells) {
10179           PetscInt *tmpCells;
10180           maxSubCells *= 2;
10181           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
10182           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
10183           ierr = PetscFree(subCells);CHKERRQ(ierr);
10184           subCells = tmpCells;
10185         }
10186         /* TOOD: Maybe overestimate then squeeze out empty faces */
10187         if (faceSize > nFV) {
10188           /* TODO: This is tricky. Maybe just add all faces */
10189           numSubFaces++;
10190         } else {
10191           numSubFaces++;
10192         }
10193         for (f = 0; f < faceSize; ++f) {
10194           subVerticesActive[subface[f]] = 1;
10195         }
10196         subCells[numSubCells++] = cell;
10197       }
10198     }
10199     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
10200     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
10201   }
10202   /* Pick out active subvertices */
10203   for (v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
10204     if (subVerticesActive[v]) {
10205       subVerticesActive[numSubVerticesActive++] = subVertices[v];
10206     }
10207   }
10208   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
10209   /* Set cone sizes */
10210   firstSubVertex = numSubCells;
10211   firstSubFace   = numSubCells+numSubVerticesActive;
10212   newFacePoint   = firstSubFace;
10213   for (c = 0; c < numSubCells; ++c) {
10214     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
10215   }
10216   for (f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
10217     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
10218   }
10219   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
10220   /* Create face cones */
10221   for (c = 0; c < numSubCells; ++c) {
10222     const PetscInt cell    = subCells[c];
10223     PetscInt      *closure = PETSC_NULL;
10224     PetscInt       closureSize, numCorners = 0, faceSize = 0;
10225 
10226     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10227     for (p = 0; p < closureSize*2; p += 2) {
10228       const PetscInt point = closure[p];
10229       if ((point >= vStart) && (point < vEnd)) {
10230         closure[numCorners++] = point;
10231       }
10232     }
10233     for (corner = 0; corner < numCorners; ++corner) {
10234       const PetscInt cellVertex = closure[corner];
10235       PetscInt       subVertex;
10236 
10237       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
10238       if (subVertex >= 0) { /* contains submesh vertex */
10239         for (i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
10240         if (i == faceSize) {
10241           face[faceSize]    = cellVertex;
10242           subface[faceSize] = numSubCells+subVertex;
10243           ++faceSize;
10244         }
10245       }
10246     }
10247     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
10248     if (faceSize >= nFV) {
10249       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
10250       /* Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron) */
10251       /*   We have to take all the faces, and discard those in the interior */
10252       /*   We check the join of the face vertices, which produces 2 cells if in the interior */
10253 #if 0
10254       /* This object just calls insert on each face that comes from subsets() */
10255       /* In fact, we can just always acll subsets(), since when we pass a single face it is a single call */
10256       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
10257       PointArray                          faceVec(face->begin(), face->end());
10258 
10259       subsets(faceVec, nFV, inserter);
10260 #endif
10261       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
10262     }
10263   }
10264   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
10265   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
10266   /* Build coordinates */
10267   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
10268   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10269   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
10270   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
10271   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
10272     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
10273   }
10274   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
10275   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
10276   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
10277   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
10278   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
10279   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
10280   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10281   for (v = 0; v < numSubVerticesActive; ++v) {
10282     const PetscInt vertex    = subVerticesActive[v];
10283     const PetscInt subVertex = firstSubVertex+v;
10284     PetscInt dof, off, sdof, soff;
10285 
10286     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
10287     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
10288     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
10289     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
10290     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
10291     for (d = 0; d < dof; ++d) {
10292       subCoords[soff+d] = coords[off+d];
10293     }
10294   }
10295   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
10296   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
10297   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
10298   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
10299 
10300   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
10301   /* Create map from submesh points to original mesh points */
10302   submesh = (DM_Plex *) (*subdm)->data;
10303   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
10304   for (c = 0; c < numSubCells; ++c) {
10305     tmpPoints[c] = subCells[c];
10306   }
10307   for (v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
10308     tmpPoints[v] = subVerticesActive[v-numSubCells];
10309   }
10310   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
10311 
10312   ierr = PetscFree(subCells);CHKERRQ(ierr);
10313   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
10314   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
10315   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
10316   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
10317   PetscFunctionReturn(0);
10318 }
10319 
10320 #undef __FUNCT__
10321 #define __FUNCT__ "DMPlexCreateNumbering_Private"
10322 /* We can easily have a form that takes an IS instead */
10323 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
10324 {
10325   PetscSection   section, globalSection;
10326   PetscInt      *numbers, p;
10327   PetscErrorCode ierr;
10328 
10329   PetscFunctionBegin;
10330   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
10331   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
10332   for (p = pStart; p < pEnd; ++p) {
10333     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
10334   }
10335   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
10336   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
10337   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
10338   for (p = pStart; p < pEnd; ++p) {
10339     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
10340   }
10341   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
10342   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
10343   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
10344   PetscFunctionReturn(0);
10345 }
10346 
10347 #undef __FUNCT__
10348 #define __FUNCT__ "DMPlexGetCellNumbering"
10349 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
10350 {
10351   DM_Plex    *mesh = (DM_Plex *) dm->data;
10352   PetscInt       cellHeight, cStart, cEnd, cMax;
10353   PetscErrorCode ierr;
10354 
10355   PetscFunctionBegin;
10356   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10357   if (!mesh->globalCellNumbers) {
10358     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
10359     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
10360     ierr = DMPlexGetHybridBounds(dm, &cMax, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
10361     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
10362     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
10363   }
10364   *globalCellNumbers = mesh->globalCellNumbers;
10365   PetscFunctionReturn(0);
10366 }
10367 
10368 #undef __FUNCT__
10369 #define __FUNCT__ "DMPlexGetVertexNumbering"
10370 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
10371 {
10372   DM_Plex    *mesh = (DM_Plex *) dm->data;
10373   PetscInt       vStart, vEnd, vMax;
10374   PetscErrorCode ierr;
10375 
10376   PetscFunctionBegin;
10377   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10378   if (!mesh->globalVertexNumbers) {
10379     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10380     ierr = DMPlexGetHybridBounds(dm, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vMax);CHKERRQ(ierr);
10381     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
10382     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
10383   }
10384   *globalVertexNumbers = mesh->globalVertexNumbers;
10385   PetscFunctionReturn(0);
10386 }
10387 
10388 #undef __FUNCT__
10389 #define __FUNCT__ "DMPlexGetSubpointMap"
10390 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
10391 {
10392   DM_Plex *mesh = (DM_Plex *) dm->data;
10393 
10394   PetscFunctionBegin;
10395   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10396   PetscValidPointer(subpointMap, 2);
10397   *subpointMap = mesh->subpointMap;
10398   PetscFunctionReturn(0);
10399 }
10400 
10401 #undef __FUNCT__
10402 #define __FUNCT__ "DMPlexSetSubpointMap"
10403 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
10404 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
10405 {
10406   DM_Plex *mesh = (DM_Plex *) dm->data;
10407 
10408   PetscFunctionBegin;
10409   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10410   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
10411   mesh->subpointMap = subpointMap;
10412   PetscFunctionReturn(0);
10413 }
10414 
10415 #undef __FUNCT__
10416 #define __FUNCT__ "DMPlexGetScale"
10417 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
10418 {
10419   DM_Plex *mesh = (DM_Plex *) dm->data;
10420 
10421   PetscFunctionBegin;
10422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10423   PetscValidPointer(scale, 3);
10424   *scale = mesh->scale[unit];
10425   PetscFunctionReturn(0);
10426 }
10427 
10428 #undef __FUNCT__
10429 #define __FUNCT__ "DMPlexSetScale"
10430 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
10431 {
10432   DM_Plex *mesh = (DM_Plex *) dm->data;
10433 
10434   PetscFunctionBegin;
10435   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10436   mesh->scale[unit] = scale;
10437   PetscFunctionReturn(0);
10438 }
10439 
10440 
10441 /*******************************************************************************
10442 This should be in a separate Discretization object, but I am not sure how to lay
10443 it out yet, so I am stuffing things here while I experiment.
10444 *******************************************************************************/
10445 #undef __FUNCT__
10446 #define __FUNCT__ "DMPlexSetFEMIntegration"
10447 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
10448                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10449                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10450                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10451                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10452                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
10453                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10454                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10455                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10456                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10457                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
10458                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
10459                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
10460                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10461                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10462                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
10463                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
10464 {
10465   DM_Plex *mesh = (DM_Plex *) dm->data;
10466 
10467   PetscFunctionBegin;
10468   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
10469   mesh->integrateResidualFEM       = integrateResidualFEM;
10470   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
10471   mesh->integrateJacobianFEM       = integrateJacobianFEM;
10472   PetscFunctionReturn(0);
10473 }
10474 
10475 #undef __FUNCT__
10476 #define __FUNCT__ "DMPlexProjectFunctionLocal"
10477 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
10478 {
10479   Vec            coordinates;
10480   PetscSection   section, cSection;
10481   PetscInt       dim, vStart, vEnd, v, c, d;
10482   PetscScalar   *values, *cArray;
10483   PetscReal     *coords;
10484   PetscErrorCode ierr;
10485 
10486   PetscFunctionBegin;
10487   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
10488   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10489   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
10490   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
10491   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10492   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
10493   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
10494   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
10495   for (v = vStart; v < vEnd; ++v) {
10496     PetscInt dof, off;
10497 
10498     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
10499     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
10500     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
10501     for (d = 0; d < dof; ++d) {
10502       coords[d] = PetscRealPart(cArray[off+d]);
10503     }
10504     for (c = 0; c < numComp; ++c) {
10505       values[c] = (*funcs[c])(coords);
10506     }
10507     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
10508   }
10509   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
10510   /* Temporary, must be replaced by a projection on the finite element basis */
10511   {
10512     PetscInt eStart = 0, eEnd = 0, e, depth;
10513 
10514     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
10515     --depth;
10516     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
10517     for (e = eStart; e < eEnd; ++e) {
10518       const PetscInt *cone = PETSC_NULL;
10519       PetscInt        coneSize, d;
10520       PetscScalar    *coordsA, *coordsB;
10521 
10522       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
10523       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
10524       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
10525       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
10526       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
10527       for (d = 0; d < dim; ++d) {
10528         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
10529       }
10530       for (c = 0; c < numComp; ++c) {
10531         values[c] = (*funcs[c])(coords);
10532       }
10533       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
10534     }
10535   }
10536 
10537   ierr = PetscFree(coords);CHKERRQ(ierr);
10538   ierr = PetscFree(values);CHKERRQ(ierr);
10539 #if 0
10540   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
10541   PetscReal      detJ;
10542 
10543   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
10544   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
10545   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV(PetscPowInt(this->_mesh->getSieve()->getMaxConeSize(),dim+1), true);
10546 
10547   for (PetscInt c = cStart; c < cEnd; ++c) {
10548     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
10549     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
10550     const int                          oSize   = pV.getSize();
10551     int                                v       = 0;
10552 
10553     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
10554     for (PetscInt cl = 0; cl < oSize; ++cl) {
10555       const PetscInt fDim;
10556 
10557       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
10558       if (pointDim) {
10559         for (PetscInt d = 0; d < fDim; ++d, ++v) {
10560           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
10561         }
10562       }
10563     }
10564     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
10565     pV.clear();
10566   }
10567   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
10568   ierr = PetscFree(values);CHKERRQ(ierr);
10569 #endif
10570   PetscFunctionReturn(0);
10571 }
10572 
10573 #undef __FUNCT__
10574 #define __FUNCT__ "DMPlexProjectFunction"
10575 /*@C
10576   DMPlexProjectFunction - This projects the given function into the function space provided.
10577 
10578   Input Parameters:
10579 + dm      - The DM
10580 . numComp - The number of components (functions)
10581 . funcs   - The coordinate functions to evaluate
10582 - mode    - The insertion mode for values
10583 
10584   Output Parameter:
10585 . X - vector
10586 
10587   Level: developer
10588 
10589   Note:
10590   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
10591   We will eventually fix it.
10592 
10593 ,seealso: DMPlexComputeL2Diff()
10594 */
10595 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
10596 {
10597   Vec            localX;
10598   PetscErrorCode ierr;
10599 
10600   PetscFunctionBegin;
10601   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10602   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
10603   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
10604   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
10605   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10606   PetscFunctionReturn(0);
10607 }
10608 
10609 #undef __FUNCT__
10610 #define __FUNCT__ "DMPlexComputeL2Diff"
10611 /*@C
10612   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
10613 
10614   Input Parameters:
10615 + dm    - The DM
10616 . quad  - The PetscQuadrature object for each field
10617 . funcs - The functions to evaluate for each field component
10618 - X     - The coefficient vector u_h
10619 
10620   Output Parameter:
10621 . diff - The diff ||u - u_h||_2
10622 
10623   Level: developer
10624 
10625 .seealso: DMPlexProjectFunction()
10626 */
10627 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff)
10628 {
10629   const PetscInt   debug = 0;
10630   PetscSection     section;
10631   Vec              localX;
10632   PetscReal       *coords, *v0, *J, *invJ, detJ;
10633   PetscReal        localDiff = 0.0;
10634   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
10635   PetscErrorCode   ierr;
10636 
10637   PetscFunctionBegin;
10638   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10639   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10640   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10641   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
10642   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10643   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
10644   for (field = 0; field < numFields; ++field) {
10645     numComponents += quad[field].numComponents;
10646   }
10647   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
10648   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
10649   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10650   for (c = cStart; c < cEnd; ++c) {
10651     const PetscScalar *x;
10652     PetscReal          elemDiff = 0.0;
10653 
10654     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
10655     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
10656     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10657 
10658     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
10659       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
10660       const PetscReal *quadPoints    = quad[field].quadPoints;
10661       const PetscReal *quadWeights   = quad[field].quadWeights;
10662       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
10663       const PetscInt   numBasisComps = quad[field].numComponents;
10664       const PetscReal *basis         = quad[field].basis;
10665       PetscInt         q, d, e, fc, f;
10666 
10667       if (debug) {
10668         char title[1024];
10669         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
10670         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
10671       }
10672       for (q = 0; q < numQuadPoints; ++q) {
10673         for (d = 0; d < dim; d++) {
10674           coords[d] = v0[d];
10675           for (e = 0; e < dim; e++) {
10676             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
10677           }
10678         }
10679         for (fc = 0; fc < numBasisComps; ++fc) {
10680           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
10681           PetscReal       interpolant = 0.0;
10682           for (f = 0; f < numBasisFuncs; ++f) {
10683             const PetscInt fidx = f*numBasisComps+fc;
10684             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
10685           }
10686           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
10687           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
10688         }
10689       }
10690       comp        += numBasisComps;
10691       fieldOffset += numBasisFuncs*numBasisComps;
10692     }
10693     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
10694     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
10695     localDiff += elemDiff;
10696   }
10697   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
10698   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
10699   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
10700   *diff = PetscSqrtReal(*diff);
10701   PetscFunctionReturn(0);
10702 }
10703 
10704 #undef __FUNCT__
10705 #define __FUNCT__ "DMPlexComputeResidualFEM"
10706 /*@
10707   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
10708 
10709   Input Parameters:
10710 + dm - The mesh
10711 . X  - Local input vector
10712 - user - The user context
10713 
10714   Output Parameter:
10715 . F  - Local output vector
10716 
10717   Note:
10718   The second member of the user context must be an FEMContext.
10719 
10720   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10721   like a GPU, or vectorize on a multicore machine.
10722 
10723 .seealso: DMPlexComputeJacobianActionFEM()
10724 */
10725 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
10726 {
10727   DM_Plex      *mesh = (DM_Plex *) dm->data;
10728   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10729   PetscQuadrature *quad = fem->quad;
10730   PetscSection     section;
10731   PetscReal       *v0, *J, *invJ, *detJ;
10732   PetscScalar     *elemVec, *u;
10733   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10734   PetscInt         cellDof = 0, numComponents = 0;
10735   PetscErrorCode   ierr;
10736 
10737   PetscFunctionBegin;
10738   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10739   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10740   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10741   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10742   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10743   numCells = cEnd - cStart;
10744   for (field = 0; field < numFields; ++field) {
10745     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10746     numComponents += quad[field].numComponents;
10747   }
10748   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10749   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10750   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
10751   for (c = cStart; c < cEnd; ++c) {
10752     const PetscScalar *x;
10753     PetscInt           i;
10754 
10755     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10756     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10757     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10758 
10759     for (i = 0; i < cellDof; ++i) {
10760       u[c*cellDof+i] = x[i];
10761     }
10762     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10763   }
10764   for (field = 0; field < numFields; ++field) {
10765     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10766     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10767     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
10768     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
10769     /* Conforming batches */
10770     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10771     PetscInt numBlocks  = 1;
10772     PetscInt batchSize  = numBlocks * blockSize;
10773     PetscInt numBatches = numBatchesTmp;
10774     PetscInt numChunks  = numCells / (numBatches*batchSize);
10775     /* Remainder */
10776     PetscInt numRemainder = numCells % (numBatches * batchSize);
10777     PetscInt offset       = numCells - numRemainder;
10778 
10779     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
10780     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10781                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10782   }
10783   for (c = cStart; c < cEnd; ++c) {
10784     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10785     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10786   }
10787   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10788   if (mesh->printFEM) {
10789     PetscMPIInt rank, numProcs;
10790     PetscInt    p;
10791 
10792     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10793     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10794     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
10795     for (p = 0; p < numProcs; ++p) {
10796       if (p == rank) {
10797         Vec f;
10798 
10799         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
10800         ierr = VecCopy(F, f);CHKERRQ(ierr);
10801         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
10802         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10803         ierr = VecDestroy(&f);CHKERRQ(ierr);
10804         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
10805       }
10806       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10807     }
10808   }
10809   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10810   PetscFunctionReturn(0);
10811 }
10812 
10813 #undef __FUNCT__
10814 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
10815 /*@C
10816   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
10817 
10818   Input Parameters:
10819 + dm - The mesh
10820 . J  - The Jacobian shell matrix
10821 . X  - Local input vector
10822 - user - The user context
10823 
10824   Output Parameter:
10825 . F  - Local output vector
10826 
10827   Note:
10828   The second member of the user context must be an FEMContext.
10829 
10830   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10831   like a GPU, or vectorize on a multicore machine.
10832 
10833 .seealso: DMPlexComputeResidualFEM()
10834 */
10835 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
10836 {
10837   DM_Plex      *mesh = (DM_Plex *) dm->data;
10838   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10839   PetscQuadrature *quad = fem->quad;
10840   PetscSection     section;
10841   JacActionCtx    *jctx;
10842   PetscReal       *v0, *J, *invJ, *detJ;
10843   PetscScalar     *elemVec, *u, *a;
10844   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10845   PetscInt         cellDof = 0;
10846   PetscErrorCode   ierr;
10847 
10848   PetscFunctionBegin;
10849   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10850   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
10851   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10852   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10853   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10854   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10855   numCells = cEnd - cStart;
10856   for (field = 0; field < numFields; ++field) {
10857     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10858   }
10859   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
10860   ierr = PetscMalloc7(numCells*cellDof,PetscScalar,&u,numCells*cellDof,PetscScalar,&a,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof,PetscScalar,&elemVec);CHKERRQ(ierr);
10861   for (c = cStart; c < cEnd; ++c) {
10862     const PetscScalar *x;
10863     PetscInt           i;
10864 
10865     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10866     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10867     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10868     for (i = 0; i < cellDof; ++i) {
10869       u[c*cellDof+i] = x[i];
10870     }
10871     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
10872     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10873     for (i = 0; i < cellDof; ++i) {
10874       a[c*cellDof+i] = x[i];
10875     }
10876     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10877   }
10878   for (field = 0; field < numFields; ++field) {
10879     const PetscInt numQuadPoints = quad[field].numQuadPoints;
10880     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
10881     /* Conforming batches */
10882     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10883     PetscInt numBlocks  = 1;
10884     PetscInt batchSize  = numBlocks * blockSize;
10885     PetscInt numBatches = numBatchesTmp;
10886     PetscInt numChunks  = numCells / (numBatches*batchSize);
10887     /* Remainder */
10888     PetscInt numRemainder = numCells % (numBatches * batchSize);
10889     PetscInt offset       = numCells - numRemainder;
10890 
10891     ierr = (*mesh->integrateJacobianActionFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, a, v0, J, invJ, detJ, fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, elemVec);CHKERRQ(ierr);
10892     ierr = (*mesh->integrateJacobianActionFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &a[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
10893                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
10894   }
10895   for (c = cStart; c < cEnd; ++c) {
10896     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
10897     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
10898   }
10899   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
10900   if (mesh->printFEM) {
10901     PetscMPIInt rank, numProcs;
10902     PetscInt    p;
10903 
10904     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
10905     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
10906     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
10907     for (p = 0; p < numProcs; ++p) {
10908       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
10909       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
10910     }
10911   }
10912   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10913   PetscFunctionReturn(0);
10914 }
10915 
10916 #undef __FUNCT__
10917 #define __FUNCT__ "DMPlexComputeJacobianFEM"
10918 /*@
10919   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
10920 
10921   Input Parameters:
10922 + dm - The mesh
10923 . X  - Local input vector
10924 - user - The user context
10925 
10926   Output Parameter:
10927 . Jac  - Jacobian matrix
10928 
10929   Note:
10930   The second member of the user context must be an FEMContext.
10931 
10932   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
10933   like a GPU, or vectorize on a multicore machine.
10934 
10935 .seealso: FormFunctionLocal()
10936 */
10937 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
10938 {
10939   DM_Plex      *mesh = (DM_Plex *) dm->data;
10940   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
10941   PetscQuadrature *quad = fem->quad;
10942   PetscSection     section;
10943   PetscReal       *v0, *J, *invJ, *detJ;
10944   PetscScalar     *elemMat, *u;
10945   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
10946   PetscInt         cellDof = 0, numComponents = 0;
10947   PetscBool        isShell;
10948   PetscErrorCode   ierr;
10949 
10950   PetscFunctionBegin;
10951   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
10952   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
10953   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
10954   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
10955   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
10956   numCells = cEnd - cStart;
10957   for (field = 0; field < numFields; ++field) {
10958     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
10959     numComponents += quad[field].numComponents;
10960   }
10961   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
10962   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
10963   ierr = PetscMalloc6(numCells*cellDof,PetscScalar,&u,numCells*dim,PetscReal,&v0,numCells*dim*dim,PetscReal,&J,numCells*dim*dim,PetscReal,&invJ,numCells,PetscReal,&detJ,numCells*cellDof*cellDof,PetscScalar,&elemMat);CHKERRQ(ierr);
10964   for (c = cStart; c < cEnd; ++c) {
10965     const PetscScalar *x;
10966     PetscInt           i;
10967 
10968     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
10969     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
10970     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10971 
10972     for (i = 0; i < cellDof; ++i) {
10973       u[c*cellDof+i] = x[i];
10974     }
10975     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
10976   }
10977   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
10978   for (fieldI = 0; fieldI < numFields; ++fieldI) {
10979     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
10980     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
10981     PetscInt       fieldJ;
10982 
10983     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
10984       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
10985       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
10986       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
10987       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
10988       /* Conforming batches */
10989       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
10990       PetscInt numBlocks  = 1;
10991       PetscInt batchSize  = numBlocks * blockSize;
10992       PetscInt numBatches = numBatchesTmp;
10993       PetscInt numChunks  = numCells / (numBatches*batchSize);
10994       /* Remainder */
10995       PetscInt numRemainder = numCells % (numBatches * batchSize);
10996       PetscInt offset       = numCells - numRemainder;
10997 
10998       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
10999       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
11000                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
11001     }
11002   }
11003   for (c = cStart; c < cEnd; ++c) {
11004     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
11005     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
11006   }
11007   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
11008 
11009   /* Assemble matrix, using the 2-step process:
11010        MatAssemblyBegin(), MatAssemblyEnd(). */
11011   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11012   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
11013 
11014   if (mesh->printFEM) {
11015     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
11016     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
11017     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
11018   }
11019   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
11020   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
11021   if (isShell) {
11022     JacActionCtx *jctx;
11023 
11024     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
11025     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
11026   }
11027   *str = SAME_NONZERO_PATTERN;
11028   PetscFunctionReturn(0);
11029 }
11030 
11031 
11032 #undef __FUNCT__
11033 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
11034 /*@C
11035   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
11036   the local section and an SF describing the section point overlap.
11037 
11038   Input Parameters:
11039   + s - The PetscSection for the local field layout
11040   . sf - The SF describing parallel layout of the section points
11041   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
11042   . label - The label specifying the points
11043   - labelValue - The label stratum specifying the points
11044 
11045   Output Parameter:
11046   . gsection - The PetscSection for the global field layout
11047 
11048   Note: This gives negative sizes and offsets to points not owned by this process
11049 
11050   Level: developer
11051 
11052 .seealso: PetscSectionCreate()
11053 @*/
11054 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
11055 {
11056   PetscInt      *neg;
11057   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
11058   PetscErrorCode ierr;
11059 
11060   PetscFunctionBegin;
11061   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
11062   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
11063   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
11064   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
11065   /* Mark ghost points with negative dof */
11066   for (p = pStart; p < pEnd; ++p) {
11067     PetscInt value;
11068 
11069     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
11070     if (value != labelValue) continue;
11071     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
11072     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
11073     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
11074     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
11075     neg[p-pStart] = -(dof+1);
11076   }
11077   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
11078   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
11079   if (nroots >= 0) {
11080     if (nroots > pEnd - pStart) {
11081       PetscInt *tmpDof;
11082       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11083       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
11084       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11085       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
11086       for (p = pStart; p < pEnd; ++p) {
11087         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
11088       }
11089       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
11090     } else {
11091       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11092       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
11093     }
11094   }
11095   /* Calculate new sizes, get proccess offset, and calculate point offsets */
11096   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11097     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
11098     (*gsection)->atlasOff[p] = off;
11099     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
11100   }
11101   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
11102   globalOff -= off;
11103   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
11104     (*gsection)->atlasOff[p] += globalOff;
11105     neg[p] = -((*gsection)->atlasOff[p]+1);
11106   }
11107   /* Put in negative offsets for ghost points */
11108   if (nroots >= 0) {
11109     if (nroots > pEnd - pStart) {
11110       PetscInt *tmpOff;
11111       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
11112       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
11113       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11114       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
11115       for (p = pStart; p < pEnd; ++p) {
11116         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
11117       }
11118       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
11119     } else {
11120       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11121       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
11122     }
11123   }
11124   ierr = PetscFree(neg);CHKERRQ(ierr);
11125   PetscFunctionReturn(0);
11126 }
11127