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