xref: /petsc/src/dm/impls/plex/plex.c (revision 3bf036e263fd78807e2931ff42d9ddcd8aae3fd4)
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, "\\documentclass{article}\n\n\
191 \\usepackage{tikz}\n\
192 \\usepackage{pgflibraryshapes}\n\
193 \\usetikzlibrary{backgrounds}\n\
194 \\usetikzlibrary{arrows}\n\
195 \\newenvironment{changemargin}[2]{%%\n\
196   \\begin{list}{}{%%\n\
197     \\setlength{\\topsep}{0pt}%%\n\
198     \\setlength{\\leftmargin}{#1}%%\n\
199     \\setlength{\\rightmargin}{#2}%%\n\
200     \\setlength{\\listparindent}{\\parindent}%%\n\
201     \\setlength{\\itemindent}{\\parindent}%%\n\
202     \\setlength{\\parsep}{\\parskip}%%\n\
203   }%%\n\
204   \\item[]}{\\end{list}}\n\n\
205 \\begin{document}\n\
206 \\section{%s}\n\
207 \\begin{changemargin}{-1cm}{0cm}\n\
208 \\begin{center}\n\
209 \\begin{tikzpicture}[scale = %g,font=\\fontsize{8}{8}\\selectfont]\n", name, 8.0/scale);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, "Mesh for process ");CHKERRQ(ierr);
276     for(p = 0; p < size; ++p) {
277       if (p > 0 && p == size-1) {
278         ierr = PetscViewerASCIIPrintf(viewer, ", and ", colors[p%numColors], p);CHKERRQ(ierr);
279       } else if (p > 0) {
280         ierr = PetscViewerASCIIPrintf(viewer, ", ", colors[p%numColors], p);CHKERRQ(ierr);
281       }
282       ierr = PetscViewerASCIIPrintf(viewer, "{\\textcolor{%s}%D}", colors[p%numColors], p);CHKERRQ(ierr);
283     }
284     ierr = PetscViewerASCIIPrintf(viewer, ".\n");CHKERRQ(ierr);
285     ierr = PetscViewerASCIIPrintf(viewer, "\\end{changemargin}\n\
286 \\end{document}\n", name);CHKERRQ(ierr);
287   } else {
288     MPI_Comm    comm = ((PetscObject) dm)->comm;
289     PetscInt   *sizes;
290     PetscInt    locDepth, depth, dim, d;
291     PetscInt    pStart, pEnd, p;
292     PetscMPIInt size;
293 
294     ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
295     ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
296     ierr = PetscViewerASCIIPrintf(viewer, "Mesh in %D dimensions:\n", dim);CHKERRQ(ierr);
297     ierr = DMPlexGetDepth(dm, &locDepth);CHKERRQ(ierr);
298     ierr = MPI_Allreduce(&locDepth, &depth, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
299     ierr = PetscMalloc(size * sizeof(PetscInt), &sizes);CHKERRQ(ierr);
300     if (depth == 1) {
301       ierr = DMPlexGetDepthStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
302       pEnd = pEnd - pStart;
303       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
304       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", 0);CHKERRQ(ierr);
305       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
306       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
307       ierr = DMPlexGetHeightStratum(dm, 0, &pStart, &pEnd);CHKERRQ(ierr);
308       pEnd = pEnd - pStart;
309       ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
310       ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", dim);CHKERRQ(ierr);
311       for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
312       ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
313     } else {
314       for (d = 0; d <= dim; d++) {
315         ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
316         pEnd = pEnd - pStart;
317         ierr = MPI_Gather(&pEnd, 1, MPIU_INT, sizes, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
318         ierr = PetscViewerASCIIPrintf(viewer, "  %D-cells:", d);CHKERRQ(ierr);
319         for (p = 0; p < size; ++p) {ierr = PetscViewerASCIIPrintf(viewer, " %D", sizes[p]);CHKERRQ(ierr);}
320         ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
321       }
322     }
323     ierr = PetscFree(sizes);CHKERRQ(ierr);
324   }
325   PetscFunctionReturn(0);
326 }
327 
328 #undef __FUNCT__
329 #define __FUNCT__ "DMView_Plex"
330 PetscErrorCode DMView_Plex(DM dm, PetscViewer viewer)
331 {
332   PetscBool      iascii, isbinary;
333   PetscErrorCode ierr;
334 
335   PetscFunctionBegin;
336   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
337   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
338   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
339   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERBINARY, &isbinary);CHKERRQ(ierr);
340   if (iascii) {
341     ierr = DMPlexView_Ascii(dm, viewer);CHKERRQ(ierr);
342 #if 0
343   } else if (isbinary) {
344     ierr = DMPlexView_Binary(dm, viewer);CHKERRQ(ierr);
345 #endif
346   } else SETERRQ1(((PetscObject)viewer)->comm,PETSC_ERR_SUP,"Viewer type %s not supported by this mesh object", ((PetscObject)viewer)->type_name);
347   PetscFunctionReturn(0);
348 }
349 
350 #undef __FUNCT__
351 #define __FUNCT__ "DMDestroy_Plex"
352 PetscErrorCode DMDestroy_Plex(DM dm)
353 {
354   DM_Plex    *mesh = (DM_Plex *) dm->data;
355   DMLabel        next = mesh->labels;
356   PetscErrorCode ierr;
357 
358   PetscFunctionBegin;
359   if (--mesh->refct > 0) {PetscFunctionReturn(0);}
360   ierr = PetscSectionDestroy(&mesh->coneSection);CHKERRQ(ierr);
361   ierr = PetscFree(mesh->cones);CHKERRQ(ierr);
362   ierr = PetscFree(mesh->coneOrientations);CHKERRQ(ierr);
363   ierr = PetscSectionDestroy(&mesh->supportSection);CHKERRQ(ierr);
364   ierr = PetscFree(mesh->supports);CHKERRQ(ierr);
365   ierr = PetscFree(mesh->facesTmp);CHKERRQ(ierr);
366   while(next) {
367     DMLabel tmp = next->next;
368 
369     ierr = DMLabelDestroy(&next);CHKERRQ(ierr);
370     next = tmp;
371   }
372   ierr = ISDestroy(&mesh->subpointMap);CHKERRQ(ierr);
373   ierr = ISDestroy(&mesh->globalVertexNumbers);CHKERRQ(ierr);
374   ierr = ISDestroy(&mesh->globalCellNumbers);CHKERRQ(ierr);
375   /* This was originally freed in DMDestroy(), but that prevents reference counting of backend objects */
376   ierr = PetscFree(mesh);CHKERRQ(ierr);
377   PetscFunctionReturn(0);
378 }
379 
380 #undef __FUNCT__
381 #define __FUNCT__ "DMPlexGetAdjacencySingleLevel_Private"
382 PetscErrorCode DMPlexGetAdjacencySingleLevel_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
383 {
384   const PetscInt *support = PETSC_NULL;
385   PetscInt        numAdj  = 0, maxAdjSize = *adjSize, supportSize, s;
386   PetscErrorCode  ierr;
387 
388   PetscFunctionBegin;
389   if (useClosure) {
390     ierr = DMPlexGetConeSize(dm, p, &supportSize);CHKERRQ(ierr);
391     ierr = DMPlexGetCone(dm, p, &support);CHKERRQ(ierr);
392     for (s = 0; s < supportSize; ++s) {
393       const PetscInt *cone = PETSC_NULL;
394       PetscInt        coneSize, c, q;
395 
396       ierr = DMPlexGetSupportSize(dm, support[s], &coneSize);CHKERRQ(ierr);
397       ierr = DMPlexGetSupport(dm, support[s], &cone);CHKERRQ(ierr);
398       for (c = 0; c < coneSize; ++c) {
399         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
400           if (cone[c] == adj[q]) break;
401         }
402         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
403       }
404     }
405   } else {
406     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
407     ierr = DMPlexGetSupport(dm, p, &support);CHKERRQ(ierr);
408     for (s = 0; s < supportSize; ++s) {
409       const PetscInt *cone = PETSC_NULL;
410       PetscInt        coneSize, c, q;
411 
412       ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
413       ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
414       for (c = 0; c < coneSize; ++c) {
415         for (q = 0; q < numAdj || (adj[numAdj++] = cone[c],0); ++q) {
416           if (cone[c] == adj[q]) break;
417         }
418         if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
419       }
420     }
421   }
422   *adjSize = numAdj;
423   PetscFunctionReturn(0);
424 }
425 
426 #undef __FUNCT__
427 #define __FUNCT__ "DMPlexGetAdjacency_Private"
428 PetscErrorCode DMPlexGetAdjacency_Private(DM dm, PetscInt p, PetscBool useClosure, const PetscInt *tmpClosure, PetscInt *adjSize, PetscInt adj[])
429 {
430   const PetscInt *star   = tmpClosure;
431   PetscInt        numAdj = 0, maxAdjSize = *adjSize, starSize, s;
432   PetscErrorCode  ierr;
433 
434   PetscFunctionBegin;
435   ierr = DMPlexGetTransitiveClosure(dm, p, useClosure, &starSize, (PetscInt **) &star);CHKERRQ(ierr);
436   for (s = 2; s < starSize*2; s += 2) {
437     const PetscInt *closure = PETSC_NULL;
438     PetscInt        closureSize, c, q;
439 
440     ierr = DMPlexGetTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
441     for (c = 0; c < closureSize*2; c += 2) {
442       for (q = 0; q < numAdj || (adj[numAdj++] = closure[c],0); ++q) {
443         if (closure[c] == adj[q]) break;
444       }
445       if (numAdj > maxAdjSize) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Invalid mesh exceeded adjacency allocation (%D)", maxAdjSize);
446     }
447     ierr = DMPlexRestoreTransitiveClosure(dm, star[s], (PetscBool)!useClosure, &closureSize, (PetscInt **) &closure);CHKERRQ(ierr);
448   }
449   *adjSize = numAdj;
450   PetscFunctionReturn(0);
451 }
452 
453 #undef __FUNCT__
454 #define __FUNCT__ "DMPlexSetPreallocationCenterDimension"
455 PetscErrorCode DMPlexSetPreallocationCenterDimension(DM dm, PetscInt preallocCenterDim)
456 {
457   DM_Plex *mesh = (DM_Plex *) dm->data;
458 
459   PetscFunctionBegin;
460   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
461   mesh->preallocCenterDim = preallocCenterDim;
462   PetscFunctionReturn(0);
463 }
464 
465 #undef __FUNCT__
466 #define __FUNCT__ "DMPlexPreallocateOperator"
467 PetscErrorCode DMPlexPreallocateOperator(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
468 {
469   DM_Plex        *mesh = (DM_Plex *) dm->data;
470   MPI_Comm           comm = ((PetscObject) dm)->comm;
471   PetscSF            sf, sfDof, sfAdj;
472   PetscSection       leafSectionAdj, rootSectionAdj, sectionAdj;
473   PetscInt           nleaves, l, p;
474   const PetscInt    *leaves;
475   const PetscSFNode *remotes;
476   PetscInt           dim, pStart, pEnd, numDof, globalOffStart, globalOffEnd, numCols;
477   PetscInt          *tmpClosure, *tmpAdj, *adj, *rootAdj, *cols, *remoteOffsets;
478   PetscInt           depth, maxConeSize, maxSupportSize, maxClosureSize, maxAdjSize, adjSize;
479   PetscLayout        rLayout;
480   PetscInt           locRows, rStart, rEnd, r;
481   PetscMPIInt        size;
482   PetscBool          useClosure, debug = PETSC_FALSE;
483   PetscErrorCode     ierr;
484 
485   PetscFunctionBegin;
486   ierr = PetscOptionsGetBool(PETSC_NULL, "-dm_view_preallocation", &debug, PETSC_NULL);CHKERRQ(ierr);
487   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
488   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
489   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
490   /* Create dof SF based on point SF */
491   if (debug) {
492     ierr = PetscPrintf(comm, "Input Section for Preallocation:\n");CHKERRQ(ierr);
493     ierr = PetscSectionView(section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
494     ierr = PetscPrintf(comm, "Input Global Section for Preallocation:\n");CHKERRQ(ierr);
495     ierr = PetscSectionView(sectionGlobal, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
496     ierr = PetscPrintf(comm, "Input SF for Preallocation:\n");CHKERRQ(ierr);
497     ierr = PetscSFView(sf, PETSC_NULL);CHKERRQ(ierr);
498   }
499   ierr = PetscSFCreateRemoteOffsets(sf, section, section, &remoteOffsets);CHKERRQ(ierr);
500   ierr = PetscSFCreateSectionSF(sf, section, remoteOffsets, section, &sfDof);CHKERRQ(ierr);
501   if (debug) {
502     ierr = PetscPrintf(comm, "Dof SF for Preallocation:\n");CHKERRQ(ierr);
503     ierr = PetscSFView(sfDof, PETSC_NULL);CHKERRQ(ierr);
504   }
505   /* Create section for dof adjacency (dof ==> # adj dof) */
506   /*   FEM:   Two points p and q are adjacent if q \in closure(star(p)), preallocCenterDim = dim   */
507   /*   FVM:   Two points p and q are adjacent if q \in star(cone(p)),    preallocCenterDim = dim-1 */
508   /*   FVM++: Two points p and q are adjacent if q \in star(closure(p)), preallocCenterDim = 0     */
509   if (mesh->preallocCenterDim == dim) {
510     useClosure = PETSC_FALSE;
511   } else if (mesh->preallocCenterDim == 0) {
512     useClosure = PETSC_TRUE;
513   } else SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Do not support preallocation with center points of dimension %d", mesh->preallocCenterDim);
514 
515   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
516   ierr = PetscSectionGetStorageSize(section, &numDof);CHKERRQ(ierr);
517   ierr = PetscSectionCreate(comm, &leafSectionAdj);CHKERRQ(ierr);
518   ierr = PetscSectionSetChart(leafSectionAdj, 0, numDof);CHKERRQ(ierr);
519   ierr = PetscSectionCreate(comm, &rootSectionAdj);CHKERRQ(ierr);
520   ierr = PetscSectionSetChart(rootSectionAdj, 0, numDof);CHKERRQ(ierr);
521   /*   Fill in the ghost dofs on the interface */
522   ierr = PetscSFGetGraph(sf, PETSC_NULL, &nleaves, &leaves, &remotes);CHKERRQ(ierr);
523   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
524   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
525   maxClosureSize = (PetscInt) (2*PetscMax(pow((PetscReal) mesh->maxConeSize, depth)+1, pow((PetscReal) mesh->maxSupportSize, depth)+1));
526   maxAdjSize     = (PetscInt) (pow((PetscReal) mesh->maxConeSize, depth)*pow((PetscReal) mesh->maxSupportSize, depth)+1);
527   ierr = PetscMalloc2(maxClosureSize,PetscInt,&tmpClosure,maxAdjSize,PetscInt,&tmpAdj);CHKERRQ(ierr);
528 
529   /*
530    ** The bootstrapping process involves six rounds with similar structure of visiting neighbors of each point.
531     1. Visit unowned points on interface, count adjacencies placing in leafSectionAdj
532        Reduce those counts to rootSectionAdj (now redundantly counting some interface points)
533     2. Visit owned points on interface, count adjacencies placing in rootSectionAdj
534        Create sfAdj connecting rootSectionAdj and leafSectionAdj
535     3. Visit unowned points on interface, write adjacencies to adj
536        Gather adj to rootAdj (note that there is redundancy in rootAdj when multiple procs find the same adjacencies)
537     4. Visit owned points on interface, write adjacencies to rootAdj
538        Remove redundancy in rootAdj
539    ** The last two traversals use transitive closure
540     5. Visit all owned points in the subdomain, count dofs for each point (sectionAdj)
541        Allocate memory addressed by sectionAdj (cols)
542     6. Visit all owned points in the subdomain, insert dof adjacencies into cols
543    ** Knowing all the column adjacencies, check ownership and sum into dnz and onz
544   */
545 
546   for (l = 0; l < nleaves; ++l) {
547     PetscInt dof, off, d, q;
548     PetscInt p = leaves[l], numAdj = maxAdjSize;
549 
550     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
551     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
552     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
553     for (q = 0; q < numAdj; ++q) {
554       PetscInt ndof, ncdof;
555 
556       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
557       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
558       for (d = off; d < off+dof; ++d) {
559         ierr = PetscSectionAddDof(leafSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
560       }
561     }
562   }
563   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
564   if (debug) {
565     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation on Leaves:\n");CHKERRQ(ierr);
566     ierr = PetscSectionView(leafSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
567   }
568   /* Get maximum remote adjacency sizes for owned dofs on interface (roots) */
569   if (size > 1) {
570     ierr = PetscSFReduceBegin(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
571     ierr = PetscSFReduceEnd(sfDof, MPIU_INT, leafSectionAdj->atlasDof, rootSectionAdj->atlasDof, MPI_SUM);CHKERRQ(ierr);
572   }
573   if (debug) {
574     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots:\n");CHKERRQ(ierr);
575     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
576   }
577   /* Add in local adjacency sizes for owned dofs on interface (roots) */
578   for (p = pStart; p < pEnd; ++p) {
579     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
580 
581     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
582     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
583     if (!dof) continue;
584     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
585     if (adof <= 0) continue;
586     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
587     for (q = 0; q < numAdj; ++q) {
588       PetscInt ndof, ncdof;
589 
590       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
591       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
592       for (d = off; d < off+dof; ++d) {
593         ierr = PetscSectionAddDof(rootSectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
594       }
595     }
596   }
597   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
598   if (debug) {
599     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after local additions:\n");CHKERRQ(ierr);
600     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
601   }
602   /* Create adj SF based on dof SF */
603   ierr = PetscSFCreateRemoteOffsets(sfDof, rootSectionAdj, leafSectionAdj, &remoteOffsets);CHKERRQ(ierr);
604   ierr = PetscSFCreateSectionSF(sfDof, rootSectionAdj, remoteOffsets, leafSectionAdj, &sfAdj);CHKERRQ(ierr);
605   if (debug) {
606     ierr = PetscPrintf(comm, "Adjacency SF for Preallocation:\n");CHKERRQ(ierr);
607     ierr = PetscSFView(sfAdj, PETSC_NULL);CHKERRQ(ierr);
608   }
609   ierr = PetscSFDestroy(&sfDof);CHKERRQ(ierr);
610   /* Create leaf adjacency */
611   ierr = PetscSectionSetUp(leafSectionAdj);CHKERRQ(ierr);
612   ierr = PetscSectionGetStorageSize(leafSectionAdj, &adjSize);CHKERRQ(ierr);
613   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &adj);CHKERRQ(ierr);
614   ierr = PetscMemzero(adj, adjSize * sizeof(PetscInt));CHKERRQ(ierr);
615   for (l = 0; l < nleaves; ++l) {
616     PetscInt dof, off, d, q;
617     PetscInt p = leaves[l], numAdj = maxAdjSize;
618 
619     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
620     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
621     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
622     for (d = off; d < off+dof; ++d) {
623       PetscInt aoff, i = 0;
624 
625       ierr = PetscSectionGetOffset(leafSectionAdj, d, &aoff);CHKERRQ(ierr);
626       for (q = 0; q < numAdj; ++q) {
627         PetscInt  ndof, ncdof, ngoff, nd;
628 
629         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
630         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
631         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
632         for (nd = 0; nd < ndof-ncdof; ++nd) {
633           adj[aoff+i] = (ngoff < 0 ? -(ngoff+1) : ngoff) + nd;
634           ++i;
635         }
636       }
637     }
638   }
639   /* Debugging */
640   if (debug) {
641     IS tmp;
642     ierr = PetscPrintf(comm, "Leaf adjacency indices\n");CHKERRQ(ierr);
643     ierr = ISCreateGeneral(comm, adjSize, adj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
644     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
645   }
646   /* Gather adjacenct indices to root */
647   ierr = PetscSectionGetStorageSize(rootSectionAdj, &adjSize);CHKERRQ(ierr);
648   ierr = PetscMalloc(adjSize * sizeof(PetscInt), &rootAdj);CHKERRQ(ierr);
649   for (r = 0; r < adjSize; ++r) {
650     rootAdj[r] = -1;
651   }
652   if (size > 1) {
653     ierr = PetscSFGatherBegin(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
654     ierr = PetscSFGatherEnd(sfAdj, MPIU_INT, adj, rootAdj);CHKERRQ(ierr);
655   }
656   ierr = PetscSFDestroy(&sfAdj);CHKERRQ(ierr);
657   ierr = PetscFree(adj);CHKERRQ(ierr);
658   /* Debugging */
659   if (debug) {
660     IS tmp;
661     ierr = PetscPrintf(comm, "Root adjacency indices after gather\n");CHKERRQ(ierr);
662     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
663     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
664   }
665   /* Add in local adjacency indices for owned dofs on interface (roots) */
666   for (p = pStart; p < pEnd; ++p) {
667     PetscInt numAdj = maxAdjSize, adof, dof, off, d, q;
668 
669     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
670     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
671     if (!dof) continue;
672     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
673     if (adof <= 0) continue;
674     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
675     for (d = off; d < off+dof; ++d) {
676       PetscInt adof, aoff, i;
677 
678       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
679       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
680       i    = adof-1;
681       for (q = 0; q < numAdj; ++q) {
682         PetscInt ndof, ncdof, ngoff, nd;
683 
684         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
685         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
686         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
687         for (nd = 0; nd < ndof-ncdof; ++nd) {
688           rootAdj[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
689           --i;
690         }
691       }
692     }
693   }
694   /* Debugging */
695   if (debug) {
696     IS tmp;
697     ierr = PetscPrintf(comm, "Root adjacency indices\n");CHKERRQ(ierr);
698     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
699     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
700   }
701   /* Compress indices */
702   ierr = PetscSectionSetUp(rootSectionAdj);CHKERRQ(ierr);
703   for (p = pStart; p < pEnd; ++p) {
704     PetscInt dof, cdof, off, d;
705     PetscInt adof, aoff;
706 
707     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
708     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
709     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
710     if (!dof) continue;
711     ierr = PetscSectionGetDof(rootSectionAdj, off, &adof);CHKERRQ(ierr);
712     if (adof <= 0) continue;
713     for (d = off; d < off+dof-cdof; ++d) {
714       ierr = PetscSectionGetDof(rootSectionAdj, d, &adof);CHKERRQ(ierr);
715       ierr = PetscSectionGetOffset(rootSectionAdj, d, &aoff);CHKERRQ(ierr);
716       ierr = PetscSortRemoveDupsInt(&adof, &rootAdj[aoff]);CHKERRQ(ierr);
717       ierr = PetscSectionSetDof(rootSectionAdj, d, adof);CHKERRQ(ierr);
718     }
719   }
720   /* Debugging */
721   if (debug) {
722     IS tmp;
723     ierr = PetscPrintf(comm, "Adjancency Section for Preallocation on Roots after compression:\n");CHKERRQ(ierr);
724     ierr = PetscSectionView(rootSectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
725     ierr = PetscPrintf(comm, "Root adjacency indices after compression\n");CHKERRQ(ierr);
726     ierr = ISCreateGeneral(comm, adjSize, rootAdj, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
727     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
728   }
729   /* Build adjacency section: Maps global indices to sets of adjacent global indices */
730   ierr = PetscSectionGetOffsetRange(sectionGlobal, &globalOffStart, &globalOffEnd);CHKERRQ(ierr);
731   ierr = PetscSectionCreate(comm, &sectionAdj);CHKERRQ(ierr);
732   ierr = PetscSectionSetChart(sectionAdj, globalOffStart, globalOffEnd);CHKERRQ(ierr);
733   for (p = pStart; p < pEnd; ++p) {
734     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
735     PetscBool found  = PETSC_TRUE;
736 
737     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
738     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
739     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
740     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
741     for (d = 0; d < dof-cdof; ++d) {
742       PetscInt ldof, rdof;
743 
744       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
745       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
746       if (ldof > 0) {
747         /* We do not own this point */
748       } else if (rdof > 0) {
749         ierr = PetscSectionSetDof(sectionAdj, goff+d, rdof);CHKERRQ(ierr);
750       } else {
751         found = PETSC_FALSE;
752       }
753     }
754     if (found) continue;
755     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
756     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
757     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
758     for (q = 0; q < numAdj; ++q) {
759       PetscInt ndof, ncdof, noff;
760 
761       /* Adjacent points may not be in the section chart */
762       if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
763       ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
764       ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
765       ierr = PetscSectionGetOffset(section, tmpAdj[q], &noff);CHKERRQ(ierr);
766       for (d = goff; d < goff+dof-cdof; ++d) {
767         ierr = PetscSectionAddDof(sectionAdj, d, ndof-ncdof);CHKERRQ(ierr);
768       }
769     }
770   }
771   ierr = PetscSectionSetUp(sectionAdj);CHKERRQ(ierr);
772   if (debug) {
773     ierr = PetscPrintf(comm, "Adjacency Section for Preallocation:\n");CHKERRQ(ierr);
774     ierr = PetscSectionView(sectionAdj, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
775   }
776   /* Get adjacent indices */
777   ierr = PetscSectionGetStorageSize(sectionAdj, &numCols);CHKERRQ(ierr);
778   ierr = PetscMalloc(numCols * sizeof(PetscInt), &cols);CHKERRQ(ierr);
779   for (p = pStart; p < pEnd; ++p) {
780     PetscInt  numAdj = maxAdjSize, dof, cdof, off, goff, d, q;
781     PetscBool found  = PETSC_TRUE;
782 
783     ierr = PetscSectionGetDof(section, p, &dof);CHKERRQ(ierr);
784     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
785     ierr = PetscSectionGetOffset(section, p, &off);CHKERRQ(ierr);
786     ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
787     for (d = 0; d < dof-cdof; ++d) {
788       PetscInt ldof, rdof;
789 
790       ierr = PetscSectionGetDof(leafSectionAdj, off+d, &ldof);CHKERRQ(ierr);
791       ierr = PetscSectionGetDof(rootSectionAdj, off+d, &rdof);CHKERRQ(ierr);
792       if (ldof > 0) {
793         /* We do not own this point */
794       } else if (rdof > 0) {
795         PetscInt aoff, roff;
796 
797         ierr = PetscSectionGetOffset(sectionAdj, goff+d, &aoff);CHKERRQ(ierr);
798         ierr = PetscSectionGetOffset(rootSectionAdj, off+d, &roff);CHKERRQ(ierr);
799         ierr = PetscMemcpy(&cols[aoff], &rootAdj[roff], rdof * sizeof(PetscInt));CHKERRQ(ierr);
800       } else {
801         found = PETSC_FALSE;
802       }
803     }
804     if (found) continue;
805     ierr = DMPlexGetAdjacency_Private(dm, p, useClosure, tmpClosure, &numAdj, tmpAdj);CHKERRQ(ierr);
806     for (d = goff; d < goff+dof-cdof; ++d) {
807       PetscInt adof, aoff, i = 0;
808 
809       ierr = PetscSectionGetDof(sectionAdj, d, &adof);CHKERRQ(ierr);
810       ierr = PetscSectionGetOffset(sectionAdj, d, &aoff);CHKERRQ(ierr);
811       for (q = 0; q < numAdj; ++q) {
812         PetscInt        ndof, ncdof, ngoff, nd;
813         const PetscInt *ncind;
814 
815         /* Adjacent points may not be in the section chart */
816         if ((tmpAdj[q] < pStart) || (tmpAdj[q] >= pEnd)) continue;
817         ierr = PetscSectionGetDof(section, tmpAdj[q], &ndof);CHKERRQ(ierr);
818         ierr = PetscSectionGetConstraintDof(section, tmpAdj[q], &ncdof);CHKERRQ(ierr);
819         ierr = PetscSectionGetConstraintIndices(section, tmpAdj[q], &ncind);CHKERRQ(ierr);
820         ierr = PetscSectionGetOffset(sectionGlobal, tmpAdj[q], &ngoff);CHKERRQ(ierr);
821         for (nd = 0; nd < ndof-ncdof; ++nd, ++i) {
822           cols[aoff+i] = ngoff < 0 ? -(ngoff+1)+nd: ngoff+nd;
823         }
824       }
825       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);
826     }
827   }
828   ierr = PetscSectionDestroy(&leafSectionAdj);CHKERRQ(ierr);
829   ierr = PetscSectionDestroy(&rootSectionAdj);CHKERRQ(ierr);
830   ierr = PetscFree(rootAdj);CHKERRQ(ierr);
831   ierr = PetscFree2(tmpClosure, tmpAdj);CHKERRQ(ierr);
832   /* Debugging */
833   if (debug) {
834     IS tmp;
835     ierr = PetscPrintf(comm, "Column indices\n");CHKERRQ(ierr);
836     ierr = ISCreateGeneral(comm, numCols, cols, PETSC_USE_POINTER, &tmp);CHKERRQ(ierr);
837     ierr = ISView(tmp, PETSC_NULL);CHKERRQ(ierr);
838   }
839   /* Create allocation vectors from adjacency graph */
840   ierr = MatGetLocalSize(A, &locRows, PETSC_NULL);CHKERRQ(ierr);
841   ierr = PetscLayoutCreate(((PetscObject) A)->comm, &rLayout);CHKERRQ(ierr);
842   ierr = PetscLayoutSetLocalSize(rLayout, locRows);CHKERRQ(ierr);
843   ierr = PetscLayoutSetBlockSize(rLayout, 1);CHKERRQ(ierr);
844   ierr = PetscLayoutSetUp(rLayout);CHKERRQ(ierr);
845   ierr = PetscLayoutGetRange(rLayout, &rStart, &rEnd);CHKERRQ(ierr);
846   ierr = PetscLayoutDestroy(&rLayout);CHKERRQ(ierr);
847   /* Only loop over blocks of rows */
848   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);
849   for (r = rStart/bs; r < rEnd/bs; ++r) {
850     const PetscInt row = r*bs;
851     PetscInt numCols, cStart, c;
852 
853     ierr = PetscSectionGetDof(sectionAdj, row, &numCols);CHKERRQ(ierr);
854     ierr = PetscSectionGetOffset(sectionAdj, row, &cStart);CHKERRQ(ierr);
855     for (c = cStart; c < cStart+numCols; ++c) {
856       if ((cols[c] >= rStart*bs) && (cols[c] < rEnd*bs)) {
857         ++dnz[r-rStart];
858         if (cols[c] >= row) {++dnzu[r-rStart];}
859       } else {
860         ++onz[r-rStart];
861         if (cols[c] >= row) {++onzu[r-rStart];}
862       }
863     }
864   }
865   if (bs > 1) {
866     for (r = 0; r < locRows/bs; ++r) {
867       dnz[r]  /= bs;
868       onz[r]  /= bs;
869       dnzu[r] /= bs;
870       onzu[r] /= bs;
871     }
872   }
873   /* Set matrix pattern */
874   ierr = MatXAIJSetPreallocation(A, bs, dnz, onz, dnzu, onzu);CHKERRQ(ierr);
875   ierr = MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
876   /* Fill matrix with zeros */
877   if (fillMatrix) {
878     PetscScalar *values;
879     PetscInt     maxRowLen = 0;
880 
881     for (r = rStart; r < rEnd; ++r) {
882       PetscInt len;
883 
884       ierr = PetscSectionGetDof(sectionAdj, r, &len);CHKERRQ(ierr);
885       maxRowLen = PetscMax(maxRowLen, len);
886     }
887     ierr = PetscMalloc(maxRowLen * sizeof(PetscScalar), &values);CHKERRQ(ierr);
888     ierr = PetscMemzero(values, maxRowLen * sizeof(PetscScalar));CHKERRQ(ierr);
889     for (r = rStart; r < rEnd; ++r) {
890       PetscInt numCols, cStart;
891 
892       ierr = PetscSectionGetDof(sectionAdj, r, &numCols);CHKERRQ(ierr);
893       ierr = PetscSectionGetOffset(sectionAdj, r, &cStart);CHKERRQ(ierr);
894       ierr = MatSetValues(A, 1, &r, numCols, &cols[cStart], values, INSERT_VALUES);CHKERRQ(ierr);
895     }
896     ierr = PetscFree(values);CHKERRQ(ierr);
897     ierr = MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
898     ierr = MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
899   }
900   ierr = PetscSectionDestroy(&sectionAdj);CHKERRQ(ierr);
901   ierr = PetscFree(cols);CHKERRQ(ierr);
902   PetscFunctionReturn(0);
903 }
904 
905 #if 0
906 #undef __FUNCT__
907 #define __FUNCT__ "DMPlexPreallocateOperator_2"
908 PetscErrorCode DMPlexPreallocateOperator_2(DM dm, PetscInt bs, PetscSection section, PetscSection sectionGlobal, PetscInt dnz[], PetscInt onz[], PetscInt dnzu[], PetscInt onzu[], Mat A, PetscBool fillMatrix)
909 {
910   PetscErrorCode ierr;
911   PetscInt c,cStart,cEnd,pStart,pEnd;
912   PetscInt *tmpClosure,*tmpAdj,*visits;
913 
914   PetscFunctionBegin;
915   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
916   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
917   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
918   maxClosureSize = 2*PetscMax(pow(mesh->maxConeSize, depth)+1, pow(mesh->maxSupportSize, depth)+1);
919   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
920   npoints = pEnd - pStart;
921   ierr = PetscMalloc3(maxClosureSize,PetscInt,&tmpClosure,npoints,PetscInt,&lvisits,npoints,PetscInt,&visits);CHKERRQ(ierr);
922   ierr = PetscMemzero(lvisits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
923   ierr = PetscMemzero(visits,(pEnd-pStart)*sizeof(PetscInt));CHKERRQ(ierr);
924   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
925   for (c=cStart; c<cEnd; c++) {
926     PetscInt *support = tmpClosure;
927     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_FALSE, &supportSize, (PetscInt**)&support);CHKERRQ(ierr);
928     for (p=0; p<supportSize; p++) {
929       lvisits[support[p]]++;
930     }
931   }
932   ierr = PetscSFReduceBegin(sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
933   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lvisits,visits,MPI_SUM);CHKERRQ(ierr);
934   ierr = PetscSFBcastBegin(sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
935   ierr = PetscSFBcastEnd  (sf,MPIU_INT,visits,lvisits);CHKERRQ(ierr);
936 
937   ierr = PetscSFGetRanks();CHKERRQ(ierr);
938 
939 
940   ierr = PetscMalloc2(maxClosureSize*maxClosureSize,PetscInt,&cellmat,npoints,PetscInt,&owner);CHKERRQ(ierr);
941   for (c=cStart; c<cEnd; c++) {
942     ierr = PetscMemzero(cellmat,maxClosureSize*maxClosureSize*sizeof(PetscInt));CHKERRQ(ierr);
943     /*
944      Depth-first walk of transitive closure.
945      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.
946      This contribution is added to dnz if owning ranks of p and q match, to onz otherwise.
947      */
948   }
949 
950   ierr = PetscSFReduceBegin(sf,MPIU_INT,ldnz,dnz,MPI_SUM);CHKERRQ(ierr);
951   ierr = PetscSFReduceEnd  (sf,MPIU_INT,lonz,onz,MPI_SUM);CHKERRQ(ierr);
952   PetscFunctionReturn(0);
953 }
954 #endif
955 
956 #undef __FUNCT__
957 #define __FUNCT__ "DMCreateMatrix_Plex"
958 PetscErrorCode DMCreateMatrix_Plex(DM dm, MatType mtype, Mat *J)
959 {
960   PetscSection   section, sectionGlobal;
961   PetscInt       bs = -1;
962   PetscInt       localSize;
963   PetscBool      isShell, isBlock, isSeqBlock, isMPIBlock, isSymBlock, isSymSeqBlock, isSymMPIBlock, isSymmetric;
964   PetscErrorCode ierr;
965 
966   PetscFunctionBegin;
967 #ifndef PETSC_USE_DYNAMIC_LIBRARIES
968   ierr = MatInitializePackage(PETSC_NULL);CHKERRQ(ierr);
969 #endif
970   if (!mtype) mtype = MATAIJ;
971   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
972   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
973   /* ierr = PetscSectionGetStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr); */
974   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal, &localSize);CHKERRQ(ierr);
975   ierr = MatCreate(((PetscObject) dm)->comm, J);CHKERRQ(ierr);
976   ierr = MatSetSizes(*J, localSize, localSize, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
977   ierr = MatSetType(*J, mtype);CHKERRQ(ierr);
978   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
979   ierr = PetscStrcmp(mtype, MATSHELL, &isShell);CHKERRQ(ierr);
980   ierr = PetscStrcmp(mtype, MATBAIJ, &isBlock);CHKERRQ(ierr);
981   ierr = PetscStrcmp(mtype, MATSEQBAIJ, &isSeqBlock);CHKERRQ(ierr);
982   ierr = PetscStrcmp(mtype, MATMPIBAIJ, &isMPIBlock);CHKERRQ(ierr);
983   ierr = PetscStrcmp(mtype, MATSBAIJ, &isSymBlock);CHKERRQ(ierr);
984   ierr = PetscStrcmp(mtype, MATSEQSBAIJ, &isSymSeqBlock);CHKERRQ(ierr);
985   ierr = PetscStrcmp(mtype, MATMPISBAIJ, &isSymMPIBlock);CHKERRQ(ierr);
986   /* Check for symmetric storage */
987   isSymmetric = (PetscBool) (isSymBlock || isSymSeqBlock || isSymMPIBlock);
988   if (isSymmetric) {
989     ierr = MatSetOption(*J, MAT_IGNORE_LOWER_TRIANGULAR, PETSC_TRUE);CHKERRQ(ierr);
990   }
991   if (!isShell) {
992     PetscBool fillMatrix = (PetscBool) !dm->prealloc_only;
993     PetscInt *dnz, *onz, *dnzu, *onzu, bsLocal;
994 
995     if (bs < 0) {
996       if (isBlock || isSeqBlock || isMPIBlock || isSymBlock || isSymSeqBlock || isSymMPIBlock) {
997         PetscInt pStart, pEnd, p, dof;
998 
999         ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1000         for (p = pStart; p < pEnd; ++p) {
1001           ierr = PetscSectionGetDof(sectionGlobal, p, &dof);CHKERRQ(ierr);
1002           if (dof) {
1003             bs = dof;
1004             break;
1005           }
1006         }
1007       } else {
1008         bs = 1;
1009       }
1010       /* Must have same blocksize on all procs (some might have no points) */
1011       bsLocal = bs;
1012       ierr = MPI_Allreduce(&bsLocal, &bs, 1, MPIU_INT, MPI_MAX, ((PetscObject) dm)->comm);CHKERRQ(ierr);
1013     }
1014     ierr = PetscMalloc4(localSize/bs, PetscInt, &dnz, localSize/bs, PetscInt, &onz, localSize/bs, PetscInt, &dnzu, localSize/bs, PetscInt, &onzu);CHKERRQ(ierr);
1015     ierr = PetscMemzero(dnz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1016     ierr = PetscMemzero(onz,  localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1017     ierr = PetscMemzero(dnzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1018     ierr = PetscMemzero(onzu, localSize/bs * sizeof(PetscInt));CHKERRQ(ierr);
1019     ierr = DMPlexPreallocateOperator(dm, bs, section, sectionGlobal, dnz, onz, dnzu, onzu, *J, fillMatrix);CHKERRQ(ierr);
1020     ierr = PetscFree4(dnz, onz, dnzu, onzu);CHKERRQ(ierr);
1021   }
1022   PetscFunctionReturn(0);
1023 }
1024 
1025 #undef __FUNCT__
1026 #define __FUNCT__ "DMPlexGetDimension"
1027 /*@
1028   DMPlexGetDimension - Return the topological mesh dimension
1029 
1030   Not collective
1031 
1032   Input Parameter:
1033 . mesh - The DMPlex
1034 
1035   Output Parameter:
1036 . dim - The topological mesh dimension
1037 
1038   Level: beginner
1039 
1040 .seealso: DMPlexCreate()
1041 @*/
1042 PetscErrorCode DMPlexGetDimension(DM dm, PetscInt *dim)
1043 {
1044   DM_Plex *mesh = (DM_Plex *) dm->data;
1045 
1046   PetscFunctionBegin;
1047   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1048   PetscValidPointer(dim, 2);
1049   *dim = mesh->dim;
1050   PetscFunctionReturn(0);
1051 }
1052 
1053 #undef __FUNCT__
1054 #define __FUNCT__ "DMPlexSetDimension"
1055 /*@
1056   DMPlexSetDimension - Set the topological mesh dimension
1057 
1058   Collective on mesh
1059 
1060   Input Parameters:
1061 + mesh - The DMPlex
1062 - dim - The topological mesh dimension
1063 
1064   Level: beginner
1065 
1066 .seealso: DMPlexCreate()
1067 @*/
1068 PetscErrorCode DMPlexSetDimension(DM dm, PetscInt dim)
1069 {
1070   DM_Plex *mesh = (DM_Plex *) dm->data;
1071 
1072   PetscFunctionBegin;
1073   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1074   PetscValidLogicalCollectiveInt(dm, dim, 2);
1075   mesh->dim = dim;
1076   mesh->preallocCenterDim = dim;
1077   PetscFunctionReturn(0);
1078 }
1079 
1080 #undef __FUNCT__
1081 #define __FUNCT__ "DMPlexGetChart"
1082 /*@
1083   DMPlexGetChart - Return the interval for all mesh points [pStart, pEnd)
1084 
1085   Not collective
1086 
1087   Input Parameter:
1088 . mesh - The DMPlex
1089 
1090   Output Parameters:
1091 + pStart - The first mesh point
1092 - pEnd   - The upper bound for mesh points
1093 
1094   Level: beginner
1095 
1096 .seealso: DMPlexCreate(), DMPlexSetChart()
1097 @*/
1098 PetscErrorCode DMPlexGetChart(DM dm, PetscInt *pStart, PetscInt *pEnd)
1099 {
1100   DM_Plex    *mesh = (DM_Plex *) dm->data;
1101   PetscErrorCode ierr;
1102 
1103   PetscFunctionBegin;
1104   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1105   ierr = PetscSectionGetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1106   PetscFunctionReturn(0);
1107 }
1108 
1109 #undef __FUNCT__
1110 #define __FUNCT__ "DMPlexSetChart"
1111 /*@
1112   DMPlexSetChart - Set the interval for all mesh points [pStart, pEnd)
1113 
1114   Not collective
1115 
1116   Input Parameters:
1117 + mesh - The DMPlex
1118 . pStart - The first mesh point
1119 - pEnd   - The upper bound for mesh points
1120 
1121   Output Parameters:
1122 
1123   Level: beginner
1124 
1125 .seealso: DMPlexCreate(), DMPlexGetChart()
1126 @*/
1127 PetscErrorCode DMPlexSetChart(DM dm, PetscInt pStart, PetscInt pEnd)
1128 {
1129   DM_Plex    *mesh = (DM_Plex *) dm->data;
1130   PetscErrorCode ierr;
1131 
1132   PetscFunctionBegin;
1133   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1134   ierr = PetscSectionSetChart(mesh->coneSection, pStart, pEnd);CHKERRQ(ierr);
1135   ierr = PetscSectionSetChart(mesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
1136   PetscFunctionReturn(0);
1137 }
1138 
1139 #undef __FUNCT__
1140 #define __FUNCT__ "DMPlexGetConeSize"
1141 /*@
1142   DMPlexGetConeSize - Return the number of in-edges for this point in the Sieve DAG
1143 
1144   Not collective
1145 
1146   Input Parameters:
1147 + mesh - The DMPlex
1148 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1149 
1150   Output Parameter:
1151 . size - The cone size for point p
1152 
1153   Level: beginner
1154 
1155 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1156 @*/
1157 PetscErrorCode DMPlexGetConeSize(DM dm, PetscInt p, PetscInt *size)
1158 {
1159   DM_Plex    *mesh = (DM_Plex *) dm->data;
1160   PetscErrorCode ierr;
1161 
1162   PetscFunctionBegin;
1163   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1164   PetscValidPointer(size, 3);
1165   ierr = PetscSectionGetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1166   PetscFunctionReturn(0);
1167 }
1168 
1169 #undef __FUNCT__
1170 #define __FUNCT__ "DMPlexSetConeSize"
1171 /*@
1172   DMPlexSetConeSize - Set the number of in-edges for this point in the Sieve DAG
1173 
1174   Not collective
1175 
1176   Input Parameters:
1177 + mesh - The DMPlex
1178 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1179 - size - The cone size for point p
1180 
1181   Output Parameter:
1182 
1183   Note:
1184   This should be called after DMPlexSetChart().
1185 
1186   Level: beginner
1187 
1188 .seealso: DMPlexCreate(), DMPlexGetConeSize(), DMPlexSetChart()
1189 @*/
1190 PetscErrorCode DMPlexSetConeSize(DM dm, PetscInt p, PetscInt size)
1191 {
1192   DM_Plex    *mesh = (DM_Plex *) dm->data;
1193   PetscErrorCode ierr;
1194 
1195   PetscFunctionBegin;
1196   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1197   ierr = PetscSectionSetDof(mesh->coneSection, p, size);CHKERRQ(ierr);
1198   mesh->maxConeSize = PetscMax(mesh->maxConeSize, size);
1199   PetscFunctionReturn(0);
1200 }
1201 
1202 #undef __FUNCT__
1203 #define __FUNCT__ "DMPlexGetCone"
1204 /*@C
1205   DMPlexGetCone - Return the points on the in-edges for this point in the Sieve DAG
1206 
1207   Not collective
1208 
1209   Input Parameters:
1210 + mesh - The DMPlex
1211 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1212 
1213   Output Parameter:
1214 . cone - An array of points which are on the in-edges for point p
1215 
1216   Level: beginner
1217 
1218   Note:
1219   This routine is not available in Fortran.
1220 
1221 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart()
1222 @*/
1223 PetscErrorCode DMPlexGetCone(DM dm, PetscInt p, const PetscInt *cone[])
1224 {
1225   DM_Plex    *mesh = (DM_Plex *) dm->data;
1226   PetscInt       off;
1227   PetscErrorCode ierr;
1228 
1229   PetscFunctionBegin;
1230   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1231   PetscValidPointer(cone, 3);
1232   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1233   *cone = &mesh->cones[off];
1234   PetscFunctionReturn(0);
1235 }
1236 
1237 #undef __FUNCT__
1238 #define __FUNCT__ "DMPlexSetCone"
1239 /*@
1240   DMPlexSetCone - Set the points on the in-edges for this point in the Sieve DAG
1241 
1242   Not collective
1243 
1244   Input Parameters:
1245 + mesh - The DMPlex
1246 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1247 - cone - An array of points which are on the in-edges for point p
1248 
1249   Output Parameter:
1250 
1251   Note:
1252   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1253 
1254   Level: beginner
1255 
1256 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1257 @*/
1258 PetscErrorCode DMPlexSetCone(DM dm, PetscInt p, const PetscInt cone[])
1259 {
1260   DM_Plex    *mesh = (DM_Plex *) dm->data;
1261   PetscInt       pStart, pEnd;
1262   PetscInt       dof, off, c;
1263   PetscErrorCode ierr;
1264 
1265   PetscFunctionBegin;
1266   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1267   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1268   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1269   if (dof) PetscValidPointer(cone, 3);
1270   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1271   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);
1272   for (c = 0; c < dof; ++c) {
1273     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);
1274     mesh->cones[off+c] = cone[c];
1275   }
1276   PetscFunctionReturn(0);
1277 }
1278 
1279 #undef __FUNCT__
1280 #define __FUNCT__ "DMPlexGetConeOrientation"
1281 /*@C
1282   DMPlexGetConeOrientation - Return the orientations on the in-edges for this point in the Sieve DAG
1283 
1284   Not collective
1285 
1286   Input Parameters:
1287 + mesh - The DMPlex
1288 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1289 
1290   Output Parameter:
1291 . coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1292                     integer giving the prescription for cone traversal. If it is negative, the cone is
1293                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1294                     the index of the cone point on which to start.
1295 
1296   Level: beginner
1297 
1298   Note:
1299   This routine is not available in Fortran.
1300 
1301 .seealso: DMPlexCreate(), DMPlexGetCone(), DMPlexSetCone(), DMPlexSetChart()
1302 @*/
1303 PetscErrorCode DMPlexGetConeOrientation(DM dm, PetscInt p, const PetscInt *coneOrientation[])
1304 {
1305   DM_Plex    *mesh = (DM_Plex *) dm->data;
1306   PetscInt       off;
1307   PetscErrorCode ierr;
1308 
1309   PetscFunctionBegin;
1310   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1311 #if defined(PETSC_USE_DEBUG)
1312   {
1313     PetscInt dof;
1314     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1315     if (dof) PetscValidPointer(coneOrientation, 3);
1316   }
1317 #endif
1318   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1319   *coneOrientation = &mesh->coneOrientations[off];
1320   PetscFunctionReturn(0);
1321 }
1322 
1323 #undef __FUNCT__
1324 #define __FUNCT__ "DMPlexSetConeOrientation"
1325 /*@
1326   DMPlexSetConeOrientation - Set the orientations on the in-edges for this point in the Sieve DAG
1327 
1328   Not collective
1329 
1330   Input Parameters:
1331 + mesh - The DMPlex
1332 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1333 - coneOrientation - An array of orientations which are on the in-edges for point p. An orientation is an
1334                     integer giving the prescription for cone traversal. If it is negative, the cone is
1335                     traversed in the opposite direction. Its value 'o', or if negative '-(o+1)', gives
1336                     the index of the cone point on which to start.
1337 
1338   Output Parameter:
1339 
1340   Note:
1341   This should be called after all calls to DMPlexSetConeSize() and DMSetUp().
1342 
1343   Level: beginner
1344 
1345 .seealso: DMPlexCreate(), DMPlexGetConeOrientation(), DMPlexSetCone(), DMPlexSetChart(), DMPlexSetConeSize(), DMSetUp()
1346 @*/
1347 PetscErrorCode DMPlexSetConeOrientation(DM dm, PetscInt p, const PetscInt coneOrientation[])
1348 {
1349   DM_Plex    *mesh = (DM_Plex *) dm->data;
1350   PetscInt       pStart, pEnd;
1351   PetscInt       dof, off, c;
1352   PetscErrorCode ierr;
1353 
1354   PetscFunctionBegin;
1355   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1356   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1357   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1358   if (dof) PetscValidPointer(coneOrientation, 3);
1359   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1360   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);
1361   for (c = 0; c < dof; ++c) {
1362     PetscInt cdof, o = coneOrientation[c];
1363 
1364     ierr = PetscSectionGetDof(mesh->coneSection, mesh->cones[off+c], &cdof);CHKERRQ(ierr);
1365     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);
1366     mesh->coneOrientations[off+c] = o;
1367   }
1368   PetscFunctionReturn(0);
1369 }
1370 
1371 #undef __FUNCT__
1372 #define __FUNCT__ "DMPlexInsertCone"
1373 PetscErrorCode DMPlexInsertCone(DM dm, PetscInt p, PetscInt conePos, PetscInt conePoint)
1374 {
1375   DM_Plex    *mesh = (DM_Plex *) dm->data;
1376   PetscInt       pStart, pEnd;
1377   PetscInt       dof, off;
1378   PetscErrorCode ierr;
1379 
1380   PetscFunctionBegin;
1381   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1382   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
1383   ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1384   ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1385   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);
1386   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);
1387   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);
1388   mesh->cones[off+conePos] = conePoint;
1389   PetscFunctionReturn(0);
1390 }
1391 
1392 #undef __FUNCT__
1393 #define __FUNCT__ "DMPlexGetSupportSize"
1394 /*@
1395   DMPlexGetSupportSize - Return the number of out-edges for this point in the Sieve DAG
1396 
1397   Not collective
1398 
1399   Input Parameters:
1400 + mesh - The DMPlex
1401 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1402 
1403   Output Parameter:
1404 . size - The support size for point p
1405 
1406   Level: beginner
1407 
1408 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart(), DMPlexGetConeSize()
1409 @*/
1410 PetscErrorCode DMPlexGetSupportSize(DM dm, PetscInt p, PetscInt *size)
1411 {
1412   DM_Plex    *mesh = (DM_Plex *) dm->data;
1413   PetscErrorCode ierr;
1414 
1415   PetscFunctionBegin;
1416   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1417   PetscValidPointer(size, 3);
1418   ierr = PetscSectionGetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1419   PetscFunctionReturn(0);
1420 }
1421 
1422 #undef __FUNCT__
1423 #define __FUNCT__ "DMPlexSetSupportSize"
1424 /*@
1425   DMPlexSetSupportSize - Set the number of out-edges for this point in the Sieve DAG
1426 
1427   Not collective
1428 
1429   Input Parameters:
1430 + mesh - The DMPlex
1431 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1432 - size - The support size for point p
1433 
1434   Output Parameter:
1435 
1436   Note:
1437   This should be called after DMPlexSetChart().
1438 
1439   Level: beginner
1440 
1441 .seealso: DMPlexCreate(), DMPlexGetSupportSize(), DMPlexSetChart()
1442 @*/
1443 PetscErrorCode DMPlexSetSupportSize(DM dm, PetscInt p, PetscInt size)
1444 {
1445   DM_Plex    *mesh = (DM_Plex *) dm->data;
1446   PetscErrorCode ierr;
1447 
1448   PetscFunctionBegin;
1449   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1450   ierr = PetscSectionSetDof(mesh->supportSection, p, size);CHKERRQ(ierr);
1451   mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, size);
1452   PetscFunctionReturn(0);
1453 }
1454 
1455 #undef __FUNCT__
1456 #define __FUNCT__ "DMPlexGetSupport"
1457 /*@C
1458   DMPlexGetSupport - Return the points on the out-edges for this point in the Sieve DAG
1459 
1460   Not collective
1461 
1462   Input Parameters:
1463 + mesh - The DMPlex
1464 - p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1465 
1466   Output Parameter:
1467 . support - An array of points which are on the out-edges for point p
1468 
1469   Level: beginner
1470 
1471 .seealso: DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1472 @*/
1473 PetscErrorCode DMPlexGetSupport(DM dm, PetscInt p, const PetscInt *support[])
1474 {
1475   DM_Plex    *mesh = (DM_Plex *) dm->data;
1476   PetscInt       off;
1477   PetscErrorCode ierr;
1478 
1479   PetscFunctionBegin;
1480   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1481   PetscValidPointer(support, 3);
1482   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1483   *support = &mesh->supports[off];
1484   PetscFunctionReturn(0);
1485 }
1486 
1487 #undef __FUNCT__
1488 #define __FUNCT__ "DMPlexSetSupport"
1489 /*@
1490   DMPlexSetSupport - Set the points on the out-edges for this point in the Sieve DAG
1491 
1492   Not collective
1493 
1494   Input Parameters:
1495 + mesh - The DMPlex
1496 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1497 - support - An array of points which are on the in-edges for point p
1498 
1499   Output Parameter:
1500 
1501   Note:
1502   This should be called after all calls to DMPlexSetSupportSize() and DMSetUp().
1503 
1504   Level: beginner
1505 
1506 .seealso: DMPlexCreate(), DMPlexGetSupport(), DMPlexSetChart(), DMPlexSetSupportSize(), DMSetUp()
1507 @*/
1508 PetscErrorCode DMPlexSetSupport(DM dm, PetscInt p, const PetscInt support[])
1509 {
1510   DM_Plex    *mesh = (DM_Plex *) dm->data;
1511   PetscInt       pStart, pEnd;
1512   PetscInt       dof, off, c;
1513   PetscErrorCode ierr;
1514 
1515   PetscFunctionBegin;
1516   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1517   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1518   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1519   if (dof) PetscValidPointer(support, 3);
1520   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1521   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);
1522   for (c = 0; c < dof; ++c) {
1523     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);
1524     mesh->supports[off+c] = support[c];
1525   }
1526   PetscFunctionReturn(0);
1527 }
1528 
1529 #undef __FUNCT__
1530 #define __FUNCT__ "DMPlexInsertSupport"
1531 PetscErrorCode DMPlexInsertSupport(DM dm, PetscInt p, PetscInt supportPos, PetscInt supportPoint)
1532 {
1533   DM_Plex    *mesh = (DM_Plex *) dm->data;
1534   PetscInt       pStart, pEnd;
1535   PetscInt       dof, off;
1536   PetscErrorCode ierr;
1537 
1538   PetscFunctionBegin;
1539   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1540   ierr = PetscSectionGetChart(mesh->supportSection, &pStart, &pEnd);CHKERRQ(ierr);
1541   ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1542   ierr = PetscSectionGetOffset(mesh->supportSection, p, &off);CHKERRQ(ierr);
1543   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);
1544   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);
1545   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);
1546   mesh->supports[off+supportPos] = supportPoint;
1547   PetscFunctionReturn(0);
1548 }
1549 
1550 #undef __FUNCT__
1551 #define __FUNCT__ "DMPlexGetTransitiveClosure"
1552 /*@C
1553   DMPlexGetTransitiveClosure - Return the points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1554 
1555   Not collective
1556 
1557   Input Parameters:
1558 + mesh - The DMPlex
1559 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1560 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1561 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1562 
1563   Output Parameters:
1564 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1565 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1566 
1567   Note:
1568   If using internal storage (points is PETSC_NULL on input), each call overwrites the last output.
1569 
1570   Level: beginner
1571 
1572 .seealso: DMPlexRestoreTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1573 @*/
1574 PetscErrorCode DMPlexGetTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1575 {
1576   DM_Plex     *mesh = (DM_Plex *) dm->data;
1577   PetscInt       *closure, *fifo;
1578   const PetscInt *tmp = PETSC_NULL, *tmpO = PETSC_NULL;
1579   PetscInt        tmpSize, t;
1580   PetscInt        depth = 0, maxSize;
1581   PetscInt        closureSize = 2, fifoSize = 0, fifoStart = 0;
1582   PetscErrorCode  ierr;
1583 
1584   PetscFunctionBegin;
1585   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1586   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1587   maxSize = (PetscInt) (2*PetscMax(PetscMax(pow((PetscReal) mesh->maxConeSize, depth)+1, pow((PetscReal) mesh->maxSupportSize, depth)+1), depth+1));
1588   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1589   if (*points) {
1590     closure = *points;
1591   } else {
1592     ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &closure);CHKERRQ(ierr);
1593   }
1594   closure[0] = p; closure[1] = 0;
1595   /* This is only 1-level */
1596   if (useCone) {
1597     ierr = DMPlexGetConeSize(dm, p, &tmpSize);CHKERRQ(ierr);
1598     ierr = DMPlexGetCone(dm, p, &tmp);CHKERRQ(ierr);
1599     ierr = DMPlexGetConeOrientation(dm, p, &tmpO);CHKERRQ(ierr);
1600   } else {
1601     ierr = DMPlexGetSupportSize(dm, p, &tmpSize);CHKERRQ(ierr);
1602     ierr = DMPlexGetSupport(dm, p, &tmp);CHKERRQ(ierr);
1603   }
1604   for (t = 0; t < tmpSize; ++t, closureSize += 2, fifoSize += 2) {
1605     const PetscInt cp = tmp[t];
1606     const PetscInt co = tmpO ? tmpO[t] : 0;
1607 
1608     closure[closureSize]   = cp;
1609     closure[closureSize+1] = co;
1610     fifo[fifoSize]         = cp;
1611     fifo[fifoSize+1]       = co;
1612   }
1613   while(fifoSize - fifoStart) {
1614     const PetscInt q   = fifo[fifoStart];
1615     const PetscInt o   = fifo[fifoStart+1];
1616     const PetscInt rev = o >= 0 ? 0 : 1;
1617     const PetscInt off = rev ? -(o+1) : o;
1618 
1619     if (useCone) {
1620       ierr = DMPlexGetConeSize(dm, q, &tmpSize);CHKERRQ(ierr);
1621       ierr = DMPlexGetCone(dm, q, &tmp);CHKERRQ(ierr);
1622       ierr = DMPlexGetConeOrientation(dm, q, &tmpO);CHKERRQ(ierr);
1623     } else {
1624       ierr = DMPlexGetSupportSize(dm, q, &tmpSize);CHKERRQ(ierr);
1625       ierr = DMPlexGetSupport(dm, q, &tmp);CHKERRQ(ierr);
1626       tmpO = PETSC_NULL;
1627     }
1628     for (t = 0; t < tmpSize; ++t) {
1629       const PetscInt i  = ((rev ? tmpSize-t : t) + off)%tmpSize;
1630       const PetscInt cp = tmp[i];
1631       /* Must propogate orientation */
1632       const PetscInt co = tmpO ? (rev ? -(tmpO[i]+1) : tmpO[i]) : 0;
1633       PetscInt       c;
1634 
1635       /* Check for duplicate */
1636       for (c = 0; c < closureSize; c += 2) {
1637         if (closure[c] == cp) break;
1638       }
1639       if (c == closureSize) {
1640         closure[closureSize]   = cp;
1641         closure[closureSize+1] = co;
1642         fifo[fifoSize]         = cp;
1643         fifo[fifoSize+1]       = co;
1644         closureSize += 2;
1645         fifoSize    += 2;
1646       }
1647     }
1648     fifoStart += 2;
1649   }
1650   if (numPoints) *numPoints = closureSize/2;
1651   if (points)    *points    = closure;
1652   ierr = DMRestoreWorkArray(dm, maxSize, PETSC_INT, &fifo);CHKERRQ(ierr);
1653   PetscFunctionReturn(0);
1654 }
1655 
1656 #undef __FUNCT__
1657 #define __FUNCT__ "DMPlexRestoreTransitiveClosure"
1658 /*@C
1659   DMPlexRestoreTransitiveClosure - Restore the array of points on the transitive closure of the in-edges or out-edges for this point in the Sieve DAG
1660 
1661   Not collective
1662 
1663   Input Parameters:
1664 + mesh - The DMPlex
1665 . p - The Sieve point, which must lie in the chart set with DMPlexSetChart()
1666 . useCone - PETSC_TRUE for in-edges,  otherwise use out-edges
1667 - points - If points is PETSC_NULL on input, internal storage will be returned, otherwise the provided array is used
1668 
1669   Output Parameters:
1670 + numPoints - The number of points in the closure, so points[] is of size 2*numPoints
1671 - points - The points and point orientations, interleaved as pairs [p0, o0, p1, o1, ...]
1672 
1673   Note:
1674   If not using internal storage (points is not PETSC_NULL on input), this call is unnecessary
1675 
1676   Level: beginner
1677 
1678 .seealso: DMPlexGetTransitiveClosure(), DMPlexCreate(), DMPlexSetCone(), DMPlexSetChart(), DMPlexGetCone()
1679 @*/
1680 PetscErrorCode DMPlexRestoreTransitiveClosure(DM dm, PetscInt p, PetscBool useCone, PetscInt *numPoints, PetscInt *points[])
1681 {
1682   PetscErrorCode  ierr;
1683 
1684   PetscFunctionBegin;
1685   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1686   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, points);CHKERRQ(ierr);
1687   PetscFunctionReturn(0);
1688 }
1689 
1690 #undef __FUNCT__
1691 #define __FUNCT__ "DMPlexGetFaces"
1692 /*
1693   DMPlexGetFaces -
1694 
1695   Note: This will only work for cell-vertex meshes.
1696 */
1697 PetscErrorCode DMPlexGetFaces(DM dm, PetscInt p, PetscInt *numFaces, PetscInt *faceSize, const PetscInt *faces[])
1698 {
1699   DM_Plex     *mesh  = (DM_Plex *) dm->data;
1700   const PetscInt *cone  = PETSC_NULL;
1701   PetscInt        depth = 0, dim, coneSize;
1702   PetscErrorCode  ierr;
1703 
1704   PetscFunctionBegin;
1705   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1706   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
1707   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
1708   if (depth > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Faces can only be returned for cell-vertex meshes.");
1709   if (!mesh->facesTmp) {ierr = PetscMalloc(PetscSqr(PetscMax(mesh->maxConeSize, mesh->maxSupportSize)) * sizeof(PetscInt), &mesh->facesTmp);CHKERRQ(ierr);}
1710   ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
1711   ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1712   switch(dim) {
1713   case 2:
1714     switch(coneSize) {
1715     case 3:
1716       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1717       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1718       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1719       *numFaces = 3;
1720       *faceSize = 2;
1721       *faces    = mesh->facesTmp;
1722       break;
1723     case 4:
1724       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1725       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1726       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[3];
1727       mesh->facesTmp[6] = cone[3]; mesh->facesTmp[7] = cone[0];
1728       *numFaces = 4;
1729       *faceSize = 2;
1730       *faces    = mesh->facesTmp;
1731       break;
1732     default:
1733       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1734     }
1735     break;
1736   case 3:
1737     switch(coneSize) {
1738     case 3:
1739       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1] = cone[1];
1740       mesh->facesTmp[2] = cone[1]; mesh->facesTmp[3] = cone[2];
1741       mesh->facesTmp[4] = cone[2]; mesh->facesTmp[5] = cone[0];
1742       *numFaces = 3;
1743       *faceSize = 2;
1744       *faces    = mesh->facesTmp;
1745       break;
1746     case 4:
1747       mesh->facesTmp[0] = cone[0]; mesh->facesTmp[1]  = cone[1]; mesh->facesTmp[2]  = cone[2];
1748       mesh->facesTmp[3] = cone[0]; mesh->facesTmp[4]  = cone[2]; mesh->facesTmp[5]  = cone[3];
1749       mesh->facesTmp[6] = cone[0]; mesh->facesTmp[7]  = cone[3]; mesh->facesTmp[8]  = cone[1];
1750       mesh->facesTmp[9] = cone[1]; mesh->facesTmp[10] = cone[3]; mesh->facesTmp[11] = cone[2];
1751       *numFaces = 4;
1752       *faceSize = 3;
1753       *faces    = mesh->facesTmp;
1754       break;
1755     default:
1756       SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size %D not supported for dimension %D", coneSize, dim);
1757     }
1758     break;
1759   default:
1760     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Dimension %D not supported", dim);
1761   }
1762   PetscFunctionReturn(0);
1763 }
1764 
1765 #undef __FUNCT__
1766 #define __FUNCT__ "DMPlexGetMaxSizes"
1767 /*@
1768   DMPlexGetMaxSizes - Return the maximum number of in-edges (cone) and out-edges (support) for any point in the Sieve DAG
1769 
1770   Not collective
1771 
1772   Input Parameter:
1773 . mesh - The DMPlex
1774 
1775   Output Parameters:
1776 + maxConeSize - The maximum number of in-edges
1777 - maxSupportSize - The maximum number of out-edges
1778 
1779   Level: beginner
1780 
1781 .seealso: DMPlexCreate(), DMPlexSetConeSize(), DMPlexSetChart()
1782 @*/
1783 PetscErrorCode DMPlexGetMaxSizes(DM dm, PetscInt *maxConeSize, PetscInt *maxSupportSize)
1784 {
1785   DM_Plex *mesh = (DM_Plex *) dm->data;
1786 
1787   PetscFunctionBegin;
1788   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1789   if (maxConeSize)    *maxConeSize    = mesh->maxConeSize;
1790   if (maxSupportSize) *maxSupportSize = mesh->maxSupportSize;
1791   PetscFunctionReturn(0);
1792 }
1793 
1794 #undef __FUNCT__
1795 #define __FUNCT__ "DMSetUp_Plex"
1796 PetscErrorCode DMSetUp_Plex(DM dm)
1797 {
1798   DM_Plex    *mesh = (DM_Plex *) dm->data;
1799   PetscInt       size;
1800   PetscErrorCode ierr;
1801 
1802   PetscFunctionBegin;
1803   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1804   ierr = PetscSectionSetUp(mesh->coneSection);CHKERRQ(ierr);
1805   ierr = PetscSectionGetStorageSize(mesh->coneSection, &size);CHKERRQ(ierr);
1806   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->cones);CHKERRQ(ierr);
1807   ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->coneOrientations);CHKERRQ(ierr);
1808   ierr = PetscMemzero(mesh->coneOrientations, size * sizeof(PetscInt));CHKERRQ(ierr);
1809   if (mesh->maxSupportSize) {
1810     ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1811     ierr = PetscSectionGetStorageSize(mesh->supportSection, &size);CHKERRQ(ierr);
1812     ierr = PetscMalloc(size * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1813   }
1814   PetscFunctionReturn(0);
1815 }
1816 
1817 #undef __FUNCT__
1818 #define __FUNCT__ "DMCreateSubDM_Plex"
1819 PetscErrorCode DMCreateSubDM_Plex(DM dm, PetscInt numFields, PetscInt fields[], IS *is, DM *subdm)
1820 {
1821   PetscSection   section, sectionGlobal;
1822   PetscInt      *subIndices;
1823   PetscInt       subSize = 0, subOff = 0, nF, f, pStart, pEnd, p;
1824   PetscErrorCode ierr;
1825 
1826   PetscFunctionBegin;
1827   if (!numFields) PetscFunctionReturn(0);
1828   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
1829   ierr = DMGetDefaultGlobalSection(dm, &sectionGlobal);CHKERRQ(ierr);
1830   if (!section) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default section for DMPlex before splitting fields");
1831   if (!sectionGlobal) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Must set default global section for DMPlex before splitting fields");
1832   ierr = PetscSectionGetNumFields(section, &nF);CHKERRQ(ierr);
1833   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);
1834   ierr = PetscSectionGetChart(sectionGlobal, &pStart, &pEnd);CHKERRQ(ierr);
1835   for (p = pStart; p < pEnd; ++p) {
1836     PetscInt gdof;
1837 
1838     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1839     if (gdof > 0) {
1840       for (f = 0; f < numFields; ++f) {
1841         PetscInt fdof, fcdof;
1842 
1843         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1844         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1845         subSize += fdof-fcdof;
1846       }
1847     }
1848   }
1849   ierr = PetscMalloc(subSize * sizeof(PetscInt), &subIndices);CHKERRQ(ierr);
1850   for (p = pStart; p < pEnd; ++p) {
1851     PetscInt gdof, goff;
1852 
1853     ierr = PetscSectionGetDof(sectionGlobal, p, &gdof);CHKERRQ(ierr);
1854     if (gdof > 0) {
1855       ierr = PetscSectionGetOffset(sectionGlobal, p, &goff);CHKERRQ(ierr);
1856       for (f = 0; f < numFields; ++f) {
1857         PetscInt fdof, fcdof, fc, f2, poff = 0;
1858 
1859         /* Can get rid of this loop by storing field information in the global section */
1860         for (f2 = 0; f2 < fields[f]; ++f2) {
1861           ierr = PetscSectionGetFieldDof(section, p, f2, &fdof);CHKERRQ(ierr);
1862           ierr = PetscSectionGetFieldConstraintDof(section, p, f2, &fcdof);CHKERRQ(ierr);
1863           poff += fdof-fcdof;
1864         }
1865         ierr = PetscSectionGetFieldDof(section, p, fields[f], &fdof);CHKERRQ(ierr);
1866         ierr = PetscSectionGetFieldConstraintDof(section, p, fields[f], &fcdof);CHKERRQ(ierr);
1867         for (fc = 0; fc < fdof-fcdof; ++fc, ++subOff) {
1868           subIndices[subOff] = goff+poff+fc;
1869         }
1870       }
1871     }
1872   }
1873   if (is) {ierr = ISCreateGeneral(((PetscObject) dm)->comm, subSize, subIndices, PETSC_OWN_POINTER, is);CHKERRQ(ierr);}
1874   if (subdm) {
1875     PetscSection subsection;
1876     PetscBool    haveNull = PETSC_FALSE;
1877     PetscInt     f, nf = 0;
1878 
1879     ierr = DMPlexClone(dm, subdm);CHKERRQ(ierr);
1880     ierr = PetscSectionCreateSubsection(section, numFields, fields, &subsection);CHKERRQ(ierr);
1881     ierr = DMSetDefaultSection(*subdm, subsection);CHKERRQ(ierr);
1882     for (f = 0; f < numFields; ++f) {
1883       (*subdm)->nullspaceConstructors[f] = dm->nullspaceConstructors[fields[f]];
1884       if ((*subdm)->nullspaceConstructors[f]) {
1885         haveNull = PETSC_TRUE;
1886         nf       = f;
1887       }
1888     }
1889     if (haveNull) {
1890       MatNullSpace nullSpace;
1891 
1892       ierr = (*(*subdm)->nullspaceConstructors[nf])(*subdm, nf, &nullSpace);CHKERRQ(ierr);
1893       ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) nullSpace);CHKERRQ(ierr);
1894       ierr = MatNullSpaceDestroy(&nullSpace);CHKERRQ(ierr);
1895     }
1896     if (dm->fields) {
1897       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);
1898       ierr = DMSetNumFields(*subdm, numFields);CHKERRQ(ierr);
1899       for (f = 0; f < numFields; ++f) {
1900         ierr = PetscOListDuplicate(dm->fields[fields[f]]->olist, &(*subdm)->fields[f]->olist);CHKERRQ(ierr);
1901       }
1902       if (numFields == 1) {
1903         MatNullSpace space;
1904         Mat          pmat;
1905 
1906         ierr = PetscObjectQuery((*subdm)->fields[0], "nullspace", (PetscObject *) &space);CHKERRQ(ierr);
1907         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nullspace", (PetscObject) space);CHKERRQ(ierr);}
1908         ierr = PetscObjectQuery((*subdm)->fields[0], "nearnullspace", (PetscObject *) &space);CHKERRQ(ierr);
1909         if (space) {ierr = PetscObjectCompose((PetscObject) *is, "nearnullspace", (PetscObject) space);CHKERRQ(ierr);}
1910         ierr = PetscObjectQuery((*subdm)->fields[0], "pmat", (PetscObject *) &pmat);CHKERRQ(ierr);
1911         if (pmat) {ierr = PetscObjectCompose((PetscObject) *is, "pmat", (PetscObject) pmat);CHKERRQ(ierr);}
1912       }
1913     }
1914   }
1915   PetscFunctionReturn(0);
1916 }
1917 
1918 #undef __FUNCT__
1919 #define __FUNCT__ "DMPlexSymmetrize"
1920 /*@
1921   DMPlexSymmetrize - Creates support (out-edge) information from cone (in-edge) inoformation
1922 
1923   Not collective
1924 
1925   Input Parameter:
1926 . mesh - The DMPlex
1927 
1928   Output Parameter:
1929 
1930   Note:
1931   This should be called after all calls to DMPlexSetCone()
1932 
1933   Level: beginner
1934 
1935 .seealso: DMPlexCreate(), DMPlexSetChart(), DMPlexSetConeSize(), DMPlexSetCone()
1936 @*/
1937 PetscErrorCode DMPlexSymmetrize(DM dm)
1938 {
1939   DM_Plex    *mesh = (DM_Plex *) dm->data;
1940   PetscInt      *offsets;
1941   PetscInt       supportSize;
1942   PetscInt       pStart, pEnd, p;
1943   PetscErrorCode ierr;
1944 
1945   PetscFunctionBegin;
1946   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1947   if (mesh->supports) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Supports were already setup in this DMPlex");
1948   /* Calculate support sizes */
1949   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
1950   for (p = pStart; p < pEnd; ++p) {
1951     PetscInt dof, off, c;
1952 
1953     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1954     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1955     for (c = off; c < off+dof; ++c) {
1956       ierr = PetscSectionAddDof(mesh->supportSection, mesh->cones[c], 1);CHKERRQ(ierr);
1957     }
1958   }
1959   for (p = pStart; p < pEnd; ++p) {
1960     PetscInt dof;
1961 
1962     ierr = PetscSectionGetDof(mesh->supportSection, p, &dof);CHKERRQ(ierr);
1963     mesh->maxSupportSize = PetscMax(mesh->maxSupportSize, dof);
1964   }
1965   ierr = PetscSectionSetUp(mesh->supportSection);CHKERRQ(ierr);
1966   /* Calculate supports */
1967   ierr = PetscSectionGetStorageSize(mesh->supportSection, &supportSize);CHKERRQ(ierr);
1968   ierr = PetscMalloc(supportSize * sizeof(PetscInt), &mesh->supports);CHKERRQ(ierr);
1969   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &offsets);CHKERRQ(ierr);
1970   ierr = PetscMemzero(offsets, (pEnd - pStart) * sizeof(PetscInt));CHKERRQ(ierr);
1971   for (p = pStart; p < pEnd; ++p) {
1972     PetscInt dof, off, c;
1973 
1974     ierr = PetscSectionGetDof(mesh->coneSection, p, &dof);CHKERRQ(ierr);
1975     ierr = PetscSectionGetOffset(mesh->coneSection, p, &off);CHKERRQ(ierr);
1976     for (c = off; c < off+dof; ++c) {
1977       const PetscInt q = mesh->cones[c];
1978       PetscInt       offS;
1979 
1980       ierr = PetscSectionGetOffset(mesh->supportSection, q, &offS);CHKERRQ(ierr);
1981       mesh->supports[offS+offsets[q]] = p;
1982       ++offsets[q];
1983     }
1984   }
1985   ierr = PetscFree(offsets);CHKERRQ(ierr);
1986   PetscFunctionReturn(0);
1987 }
1988 
1989 #undef __FUNCT__
1990 #define __FUNCT__ "DMPlexSetDepth_Private"
1991 PetscErrorCode DMPlexSetDepth_Private(DM dm, PetscInt p, PetscInt *depth)
1992 {
1993   PetscInt       d;
1994   PetscErrorCode ierr;
1995 
1996   PetscFunctionBegin;
1997   ierr = DMPlexGetLabelValue(dm, "depth", p, &d);CHKERRQ(ierr);
1998   if (d < 0) {
1999     /* We are guaranteed that the point has a cone since the depth was not yet set */
2000     const PetscInt *cone = PETSC_NULL;
2001     PetscInt        dCone;
2002 
2003     ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
2004     ierr = DMPlexSetDepth_Private(dm, cone[0], &dCone);CHKERRQ(ierr);
2005     d    = dCone+1;
2006     ierr = DMPlexSetLabelValue(dm, "depth", p, d);CHKERRQ(ierr);
2007   }
2008   *depth = d;
2009   PetscFunctionReturn(0);
2010 }
2011 
2012 #undef __FUNCT__
2013 #define __FUNCT__ "DMPlexStratify"
2014 /*@
2015   DMPlexStratify - The Sieve DAG for most topologies is a graded poset (http://en.wikipedia.org/wiki/Graded_poset), and
2016   can be illustrated by Hasse Diagram (a http://en.wikipedia.org/wiki/Hasse_diagram). The strata group all points of the
2017   same grade, and this function calculates the strata. This grade can be seen as the height (or depth) of the point in
2018   the DAG.
2019 
2020   Not collective
2021 
2022   Input Parameter:
2023 . mesh - The DMPlex
2024 
2025   Output Parameter:
2026 
2027   Notes:
2028   The normal association for the point grade is element dimension (or co-dimension). For instance, all vertices would
2029   have depth 0, and all edges depth 1. Likewise, all cells heights would have height 0, and all faces height 1.
2030 
2031   This should be called after all calls to DMPlexSymmetrize()
2032 
2033   Level: beginner
2034 
2035 .seealso: DMPlexCreate(), DMPlexSymmetrize()
2036 @*/
2037 PetscErrorCode DMPlexStratify(DM dm)
2038 {
2039   DM_Plex    *mesh = (DM_Plex *) dm->data;
2040   PetscInt       pStart, pEnd, p;
2041   PetscInt       numRoots = 0, numLeaves = 0;
2042   PetscErrorCode ierr;
2043 
2044   PetscFunctionBegin;
2045   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2046   ierr = PetscLogEventBegin(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2047   /* Calculate depth */
2048   ierr = PetscSectionGetChart(mesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
2049   /* Initialize roots and count leaves */
2050   for (p = pStart; p < pEnd; ++p) {
2051     PetscInt coneSize, supportSize;
2052 
2053     ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2054     ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2055     if (!coneSize && supportSize) {
2056       ++numRoots;
2057       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2058     } else if (!supportSize && coneSize) {
2059       ++numLeaves;
2060     } else if (!supportSize && !coneSize) {
2061       /* Isolated points */
2062       ierr = DMPlexSetLabelValue(dm, "depth", p, 0);CHKERRQ(ierr);
2063     }
2064   }
2065   if (numRoots + numLeaves == (pEnd - pStart)) {
2066     for (p = pStart; p < pEnd; ++p) {
2067       PetscInt coneSize, supportSize;
2068 
2069       ierr = DMPlexGetConeSize(dm, p, &coneSize);CHKERRQ(ierr);
2070       ierr = DMPlexGetSupportSize(dm, p, &supportSize);CHKERRQ(ierr);
2071       if (!supportSize && coneSize) {
2072         ierr = DMPlexSetLabelValue(dm, "depth", p, 1);CHKERRQ(ierr);
2073       }
2074     }
2075   } else {
2076     /* This might be slow since lookup is not fast */
2077     for (p = pStart; p < pEnd; ++p) {
2078       PetscInt depth;
2079 
2080       ierr = DMPlexSetDepth_Private(dm, p, &depth);CHKERRQ(ierr);
2081     }
2082   }
2083   ierr = PetscLogEventEnd(DMPLEX_Stratify,dm,0,0,0);CHKERRQ(ierr);
2084   PetscFunctionReturn(0);
2085 }
2086 
2087 #undef __FUNCT__
2088 #define __FUNCT__ "DMPlexGetJoin"
2089 /*@C
2090   DMPlexGetJoin - Get an array for the join of the set of points
2091 
2092   Not Collective
2093 
2094   Input Parameters:
2095 + dm - The DMPlex object
2096 . numPoints - The number of input points for the join
2097 - points - The input points
2098 
2099   Output Parameters:
2100 + numCoveredPoints - The number of points in the join
2101 - coveredPoints - The points in the join
2102 
2103   Level: intermediate
2104 
2105   Note: Currently, this is restricted to a single level join
2106 
2107 .keywords: mesh
2108 .seealso: DMPlexRestoreJoin(), DMPlexGetMeet()
2109 @*/
2110 PetscErrorCode DMPlexGetJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2111 {
2112   DM_Plex    *mesh = (DM_Plex *) dm->data;
2113   PetscInt      *join[2];
2114   PetscInt       joinSize, i = 0;
2115   PetscInt       dof, off, p, c, m;
2116   PetscErrorCode ierr;
2117 
2118   PetscFunctionBegin;
2119   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2120   PetscValidPointer(points, 2);
2121   PetscValidPointer(numCoveredPoints, 3);
2122   PetscValidPointer(coveredPoints, 4);
2123   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2124   ierr = DMGetWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2125   /* Copy in support of first point */
2126   ierr = PetscSectionGetDof(mesh->supportSection, points[0], &dof);CHKERRQ(ierr);
2127   ierr = PetscSectionGetOffset(mesh->supportSection, points[0], &off);CHKERRQ(ierr);
2128   for (joinSize = 0; joinSize < dof; ++joinSize) {
2129     join[i][joinSize] = mesh->supports[off+joinSize];
2130   }
2131   /* Check each successive support */
2132   for (p = 1; p < numPoints; ++p) {
2133     PetscInt newJoinSize = 0;
2134 
2135     ierr = PetscSectionGetDof(mesh->supportSection, points[p], &dof);CHKERRQ(ierr);
2136     ierr = PetscSectionGetOffset(mesh->supportSection, points[p], &off);CHKERRQ(ierr);
2137     for (c = 0; c < dof; ++c) {
2138       const PetscInt point = mesh->supports[off+c];
2139 
2140       for (m = 0; m < joinSize; ++m) {
2141         if (point == join[i][m]) {
2142           join[1-i][newJoinSize++] = point;
2143           break;
2144         }
2145       }
2146     }
2147     joinSize = newJoinSize;
2148     i = 1-i;
2149   }
2150   *numCoveredPoints = joinSize;
2151   *coveredPoints    = join[i];
2152   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2153   PetscFunctionReturn(0);
2154 }
2155 
2156 #undef __FUNCT__
2157 #define __FUNCT__ "DMPlexRestoreJoin"
2158 /*@C
2159   DMPlexRestoreJoin - Restore an array for the join of the set of points
2160 
2161   Not Collective
2162 
2163   Input Parameters:
2164 + dm - The DMPlex object
2165 . numPoints - The number of input points for the join
2166 - points - The input points
2167 
2168   Output Parameters:
2169 + numCoveredPoints - The number of points in the join
2170 - coveredPoints - The points in the join
2171 
2172   Level: intermediate
2173 
2174 .keywords: mesh
2175 .seealso: DMPlexGetJoin(), DMPlexGetFullJoin(), DMPlexGetMeet()
2176 @*/
2177 PetscErrorCode DMPlexRestoreJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2178 {
2179   PetscErrorCode ierr;
2180 
2181   PetscFunctionBegin;
2182   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2183   PetscValidPointer(coveredPoints, 4);
2184   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2185   PetscFunctionReturn(0);
2186 }
2187 
2188 #undef __FUNCT__
2189 #define __FUNCT__ "DMPlexGetFullJoin"
2190 /*@C
2191   DMPlexGetFullJoin - Get an array for the join of the set of points
2192 
2193   Not Collective
2194 
2195   Input Parameters:
2196 + dm - The DMPlex object
2197 . numPoints - The number of input points for the join
2198 - points - The input points
2199 
2200   Output Parameters:
2201 + numCoveredPoints - The number of points in the join
2202 - coveredPoints - The points in the join
2203 
2204   Level: intermediate
2205 
2206 .keywords: mesh
2207 .seealso: DMPlexGetJoin(), DMPlexRestoreJoin(), DMPlexGetMeet()
2208 @*/
2209 PetscErrorCode DMPlexGetFullJoin(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2210 {
2211   DM_Plex    *mesh = (DM_Plex *) dm->data;
2212   PetscInt      *offsets, **closures;
2213   PetscInt      *join[2];
2214   PetscInt       depth = 0, maxSize, joinSize = 0, i = 0;
2215   PetscInt       p, d, c, m;
2216   PetscErrorCode ierr;
2217 
2218   PetscFunctionBegin;
2219   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2220   PetscValidPointer(points, 2);
2221   PetscValidPointer(numCoveredPoints, 3);
2222   PetscValidPointer(coveredPoints, 4);
2223 
2224   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2225   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2226   ierr = PetscMemzero(closures,numPoints*sizeof(PetscInt*));CHKERRQ(ierr);
2227   ierr = DMGetWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2228   maxSize = (PetscInt) (pow((PetscReal) mesh->maxSupportSize, depth)+1);
2229   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[0]);CHKERRQ(ierr);
2230   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &join[1]);CHKERRQ(ierr);
2231 
2232   for (p = 0; p < numPoints; ++p) {
2233     PetscInt closureSize;
2234 
2235     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_FALSE, &closureSize, &closures[p]);CHKERRQ(ierr);
2236     offsets[p*(depth+2)+0] = 0;
2237     for (d = 0; d < depth+1; ++d) {
2238       PetscInt pStart, pEnd, i;
2239 
2240       ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
2241       for (i = offsets[p*(depth+2)+d]; i < closureSize; ++i) {
2242         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2243           offsets[p*(depth+2)+d+1] = i;
2244           break;
2245         }
2246       }
2247       if (i == closureSize) offsets[p*(depth+2)+d+1] = i;
2248     }
2249     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);
2250   }
2251   for (d = 0; d < depth+1; ++d) {
2252     PetscInt dof;
2253 
2254     /* Copy in support of first point */
2255     dof = offsets[d+1] - offsets[d];
2256     for (joinSize = 0; joinSize < dof; ++joinSize) {
2257       join[i][joinSize] = closures[0][(offsets[d]+joinSize)*2];
2258     }
2259     /* Check each successive cone */
2260     for (p = 1; p < numPoints && joinSize; ++p) {
2261       PetscInt newJoinSize = 0;
2262 
2263       dof = offsets[p*(depth+2)+d+1] - offsets[p*(depth+2)+d];
2264       for (c = 0; c < dof; ++c) {
2265         const PetscInt point = closures[p][(offsets[p*(depth+2)+d]+c)*2];
2266 
2267         for (m = 0; m < joinSize; ++m) {
2268           if (point == join[i][m]) {
2269             join[1-i][newJoinSize++] = point;
2270             break;
2271           }
2272         }
2273       }
2274       joinSize = newJoinSize;
2275       i = 1-i;
2276     }
2277     if (joinSize) break;
2278   }
2279   *numCoveredPoints = joinSize;
2280   *coveredPoints    = join[i];
2281   for (p = 0; p < numPoints; ++p) {
2282     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_FALSE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2283   }
2284   ierr = PetscFree(closures);CHKERRQ(ierr);
2285   ierr = DMRestoreWorkArray(dm, numPoints*(depth+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2286   ierr = DMRestoreWorkArray(dm, mesh->maxSupportSize, PETSC_INT, &join[1-i]);CHKERRQ(ierr);
2287   PetscFunctionReturn(0);
2288 }
2289 
2290 #undef __FUNCT__
2291 #define __FUNCT__ "DMPlexGetMeet"
2292 /*@C
2293   DMPlexGetMeet - Get an array for the meet of the set of points
2294 
2295   Not Collective
2296 
2297   Input Parameters:
2298 + dm - The DMPlex object
2299 . numPoints - The number of input points for the meet
2300 - points - The input points
2301 
2302   Output Parameters:
2303 + numCoveredPoints - The number of points in the meet
2304 - coveredPoints - The points in the meet
2305 
2306   Level: intermediate
2307 
2308   Note: Currently, this is restricted to a single level meet
2309 
2310 .keywords: mesh
2311 .seealso: DMPlexRestoreMeet(), DMPlexGetJoin()
2312 @*/
2313 PetscErrorCode DMPlexGetMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveringPoints, const PetscInt **coveringPoints)
2314 {
2315   DM_Plex    *mesh = (DM_Plex *) dm->data;
2316   PetscInt      *meet[2];
2317   PetscInt       meetSize, i = 0;
2318   PetscInt       dof, off, p, c, m;
2319   PetscErrorCode ierr;
2320 
2321   PetscFunctionBegin;
2322   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2323   PetscValidPointer(points, 2);
2324   PetscValidPointer(numCoveringPoints, 3);
2325   PetscValidPointer(coveringPoints, 4);
2326   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2327   ierr = DMGetWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2328   /* Copy in cone of first point */
2329   ierr = PetscSectionGetDof(mesh->coneSection, points[0], &dof);CHKERRQ(ierr);
2330   ierr = PetscSectionGetOffset(mesh->coneSection, points[0], &off);CHKERRQ(ierr);
2331   for (meetSize = 0; meetSize < dof; ++meetSize) {
2332     meet[i][meetSize] = mesh->cones[off+meetSize];
2333   }
2334   /* Check each successive cone */
2335   for (p = 1; p < numPoints; ++p) {
2336     PetscInt newMeetSize = 0;
2337 
2338     ierr = PetscSectionGetDof(mesh->coneSection, points[p], &dof);CHKERRQ(ierr);
2339     ierr = PetscSectionGetOffset(mesh->coneSection, points[p], &off);CHKERRQ(ierr);
2340     for (c = 0; c < dof; ++c) {
2341       const PetscInt point = mesh->cones[off+c];
2342 
2343       for (m = 0; m < meetSize; ++m) {
2344         if (point == meet[i][m]) {
2345           meet[1-i][newMeetSize++] = point;
2346           break;
2347         }
2348       }
2349     }
2350     meetSize = newMeetSize;
2351     i = 1-i;
2352   }
2353   *numCoveringPoints = meetSize;
2354   *coveringPoints    = meet[i];
2355   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2356   PetscFunctionReturn(0);
2357 }
2358 
2359 #undef __FUNCT__
2360 #define __FUNCT__ "DMPlexRestoreMeet"
2361 /*@C
2362   DMPlexRestoreMeet - Restore an array for the meet of the set of points
2363 
2364   Not Collective
2365 
2366   Input Parameters:
2367 + dm - The DMPlex object
2368 . numPoints - The number of input points for the meet
2369 - points - The input points
2370 
2371   Output Parameters:
2372 + numCoveredPoints - The number of points in the meet
2373 - coveredPoints - The points in the meet
2374 
2375   Level: intermediate
2376 
2377 .keywords: mesh
2378 .seealso: DMPlexGetMeet(), DMPlexGetFullMeet(), DMPlexGetJoin()
2379 @*/
2380 PetscErrorCode DMPlexRestoreMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2381 {
2382   PetscErrorCode ierr;
2383 
2384   PetscFunctionBegin;
2385   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2386   PetscValidPointer(coveredPoints, 4);
2387   ierr = DMRestoreWorkArray(dm, 0, PETSC_INT, (void *) coveredPoints);CHKERRQ(ierr);
2388   PetscFunctionReturn(0);
2389 }
2390 
2391 #undef __FUNCT__
2392 #define __FUNCT__ "DMPlexGetFullMeet"
2393 /*@C
2394   DMPlexGetFullMeet - Get an array for the meet of the set of points
2395 
2396   Not Collective
2397 
2398   Input Parameters:
2399 + dm - The DMPlex object
2400 . numPoints - The number of input points for the meet
2401 - points - The input points
2402 
2403   Output Parameters:
2404 + numCoveredPoints - The number of points in the meet
2405 - coveredPoints - The points in the meet
2406 
2407   Level: intermediate
2408 
2409 .keywords: mesh
2410 .seealso: DMPlexGetMeet(), DMPlexRestoreMeet(), DMPlexGetJoin()
2411 @*/
2412 PetscErrorCode DMPlexGetFullMeet(DM dm, PetscInt numPoints, const PetscInt points[], PetscInt *numCoveredPoints, const PetscInt **coveredPoints)
2413 {
2414   DM_Plex    *mesh = (DM_Plex *) dm->data;
2415   PetscInt      *offsets, **closures;
2416   PetscInt      *meet[2];
2417   PetscInt       height = 0, maxSize, meetSize = 0, i = 0;
2418   PetscInt       p, h, c, m;
2419   PetscErrorCode ierr;
2420 
2421   PetscFunctionBegin;
2422   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2423   PetscValidPointer(points, 2);
2424   PetscValidPointer(numCoveredPoints, 3);
2425   PetscValidPointer(coveredPoints, 4);
2426 
2427   ierr = DMPlexGetDepth(dm, &height);CHKERRQ(ierr);
2428   ierr = PetscMalloc(numPoints * sizeof(PetscInt *), &closures);CHKERRQ(ierr);
2429   ierr = DMGetWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2430   maxSize = (PetscInt) (pow((PetscReal) mesh->maxConeSize, height)+1);
2431   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[0]);CHKERRQ(ierr);
2432   ierr = DMGetWorkArray(dm, maxSize, PETSC_INT, &meet[1]);CHKERRQ(ierr);
2433 
2434   for (p = 0; p < numPoints; ++p) {
2435     PetscInt closureSize;
2436 
2437     ierr = DMPlexGetTransitiveClosure(dm, points[p], PETSC_TRUE, &closureSize, &closures[p]);CHKERRQ(ierr);
2438     offsets[p*(height+2)+0] = 0;
2439     for (h = 0; h < height+1; ++h) {
2440       PetscInt pStart, pEnd, i;
2441 
2442       ierr = DMPlexGetHeightStratum(dm, h, &pStart, &pEnd);CHKERRQ(ierr);
2443       for (i = offsets[p*(height+2)+h]; i < closureSize; ++i) {
2444         if ((pStart > closures[p][i*2]) || (pEnd <= closures[p][i*2])) {
2445           offsets[p*(height+2)+h+1] = i;
2446           break;
2447         }
2448       }
2449       if (i == closureSize) offsets[p*(height+2)+h+1] = i;
2450     }
2451     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);
2452   }
2453   for (h = 0; h < height+1; ++h) {
2454     PetscInt dof;
2455 
2456     /* Copy in cone of first point */
2457     dof = offsets[h+1] - offsets[h];
2458     for (meetSize = 0; meetSize < dof; ++meetSize) {
2459       meet[i][meetSize] = closures[0][(offsets[h]+meetSize)*2];
2460     }
2461     /* Check each successive cone */
2462     for (p = 1; p < numPoints && meetSize; ++p) {
2463       PetscInt newMeetSize = 0;
2464 
2465       dof = offsets[p*(height+2)+h+1] - offsets[p*(height+2)+h];
2466       for (c = 0; c < dof; ++c) {
2467         const PetscInt point = closures[p][(offsets[p*(height+2)+h]+c)*2];
2468 
2469         for (m = 0; m < meetSize; ++m) {
2470           if (point == meet[i][m]) {
2471             meet[1-i][newMeetSize++] = point;
2472             break;
2473           }
2474         }
2475       }
2476       meetSize = newMeetSize;
2477       i = 1-i;
2478     }
2479     if (meetSize) break;
2480   }
2481   *numCoveredPoints = meetSize;
2482   *coveredPoints    = meet[i];
2483   for (p = 0; p < numPoints; ++p) {
2484     ierr = DMPlexRestoreTransitiveClosure(dm, points[p], PETSC_TRUE, PETSC_NULL, &closures[p]);CHKERRQ(ierr);
2485   }
2486   ierr = PetscFree(closures);CHKERRQ(ierr);
2487   ierr = DMRestoreWorkArray(dm, numPoints*(height+2), PETSC_INT, &offsets);CHKERRQ(ierr);
2488   ierr = DMRestoreWorkArray(dm, mesh->maxConeSize, PETSC_INT, &meet[1-i]);CHKERRQ(ierr);
2489   PetscFunctionReturn(0);
2490 }
2491 
2492 #undef __FUNCT__
2493 #define __FUNCT__ "DMPlexGetNumFaceVertices"
2494 static PetscErrorCode DMPlexGetNumFaceVertices(DM dm, PetscInt numCorners, PetscInt *numFaceVertices) {
2495   MPI_Comm       comm = ((PetscObject) dm)->comm;
2496   PetscInt       cellDim;
2497   PetscErrorCode ierr;
2498 
2499   PetscFunctionBegin;
2500   PetscValidPointer(numFaceVertices,3);
2501   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
2502   switch(cellDim) {
2503   case 0:
2504     *numFaceVertices = 0;
2505     break;
2506   case 1:
2507     *numFaceVertices = 1;
2508     break;
2509   case 2:
2510     switch(numCorners) {
2511     case 3: // triangle
2512       *numFaceVertices = 2; // Edge has 2 vertices
2513       break;
2514     case 4: // quadrilateral
2515       *numFaceVertices = 2; // Edge has 2 vertices
2516       break;
2517     case 6: // quadratic triangle, tri and quad cohesive Lagrange cells
2518       *numFaceVertices = 3; // Edge has 3 vertices
2519       break;
2520     case 9: // quadratic quadrilateral, quadratic quad cohesive Lagrange cells
2521       *numFaceVertices = 3; // Edge has 3 vertices
2522       break;
2523     default:
2524       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2525     }
2526     break;
2527   case 3:
2528     switch(numCorners)	{
2529     case 4: // tetradehdron
2530       *numFaceVertices = 3; // Face has 3 vertices
2531       break;
2532     case 6: // tet cohesive cells
2533       *numFaceVertices = 4; // Face has 4 vertices
2534       break;
2535     case 8: // hexahedron
2536       *numFaceVertices = 4; // Face has 4 vertices
2537       break;
2538     case 9: // tet cohesive Lagrange cells
2539       *numFaceVertices = 6; // Face has 6 vertices
2540       break;
2541     case 10: // quadratic tetrahedron
2542       *numFaceVertices = 6; // Face has 6 vertices
2543       break;
2544     case 12: // hex cohesive Lagrange cells
2545       *numFaceVertices = 6; // Face has 6 vertices
2546       break;
2547     case 18: // quadratic tet cohesive Lagrange cells
2548       *numFaceVertices = 6; // Face has 6 vertices
2549       break;
2550     case 27: // quadratic hexahedron, quadratic hex cohesive Lagrange cells
2551       *numFaceVertices = 9; // Face has 9 vertices
2552       break;
2553     default:
2554       SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid number of face corners %d for dimension %d", numCorners, cellDim);
2555     }
2556     break;
2557   default:
2558     SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid cell dimension %d", cellDim);
2559   }
2560   PetscFunctionReturn(0);
2561 }
2562 
2563 #undef __FUNCT__
2564 #define __FUNCT__ "DMPlexCreateNeighborCSR"
2565 PetscErrorCode DMPlexCreateNeighborCSR(DM dm, PetscInt *numVertices, PetscInt **offsets, PetscInt **adjacency) {
2566   const PetscInt maxFaceCases = 30;
2567   PetscInt       numFaceCases = 0;
2568   PetscInt       numFaceVertices[30]; /* maxFaceCases, C89 sucks sucks sucks */
2569   PetscInt      *off, *adj;
2570   PetscInt      *neighborCells, *tmpClosure;
2571   PetscInt       maxConeSize, maxSupportSize, maxClosure, maxNeighbors;
2572   PetscInt       dim, depth = 0, cStart, cEnd, c, numCells, cell;
2573   PetscErrorCode ierr;
2574 
2575   PetscFunctionBegin;
2576   /* For parallel partitioning, I think you have to communicate supports */
2577   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
2578   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
2579   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2580   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
2581   if (cEnd - cStart == 0) {
2582     if (numVertices) *numVertices = 0;
2583     if (offsets)     *offsets     = PETSC_NULL;
2584     if (adjacency)   *adjacency   = PETSC_NULL;
2585     PetscFunctionReturn(0);
2586   }
2587   numCells = cEnd - cStart;
2588   /* Setup face recognition */
2589   {
2590     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 */
2591 
2592     for (c = cStart; c < cEnd; ++c) {
2593       PetscInt corners;
2594 
2595       ierr = DMPlexGetConeSize(dm, c, &corners);CHKERRQ(ierr);
2596       if (!cornersSeen[corners]) {
2597         PetscInt nFV;
2598 
2599         if (numFaceCases >= maxFaceCases) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Exceeded maximum number of face recognition cases");
2600         cornersSeen[corners] = 1;
2601         ierr = DMPlexGetNumFaceVertices(dm, corners, &nFV);CHKERRQ(ierr);
2602         numFaceVertices[numFaceCases++] = nFV;
2603       }
2604     }
2605   }
2606   maxClosure   = (PetscInt) (2*PetscMax(pow((PetscReal) maxConeSize, depth)+1, pow((PetscReal) maxSupportSize, depth)+1));
2607   maxNeighbors = (PetscInt) (pow((PetscReal) maxConeSize, depth)*pow((PetscReal) maxSupportSize, depth)+1);
2608   ierr = PetscMalloc2(maxNeighbors,PetscInt,&neighborCells,maxClosure,PetscInt,&tmpClosure);CHKERRQ(ierr);
2609   ierr = PetscMalloc((numCells+1) * sizeof(PetscInt), &off);CHKERRQ(ierr);
2610   ierr = PetscMemzero(off, (numCells+1) * sizeof(PetscInt));CHKERRQ(ierr);
2611   /* Count neighboring cells */
2612   for (cell = cStart; cell < cEnd; ++cell) {
2613     PetscInt numNeighbors = maxNeighbors, n;
2614 
2615     ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2616     /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2617     for (n = 0; n < numNeighbors; ++n) {
2618       PetscInt        cellPair[2] = {cell, neighborCells[n]};
2619       PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2620       PetscInt        meetSize    = 0;
2621       const PetscInt *meet        = PETSC_NULL;
2622 
2623       if (cellPair[0] == cellPair[1]) continue;
2624       if (!found) {
2625         ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2626         if (meetSize) {
2627           PetscInt f;
2628 
2629           for (f = 0; f < numFaceCases; ++f) {
2630             if (numFaceVertices[f] == meetSize) {
2631               found = PETSC_TRUE;
2632               break;
2633             }
2634           }
2635         }
2636         ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2637       }
2638       if (found) {
2639         ++off[cell-cStart+1];
2640       }
2641     }
2642   }
2643   /* Prefix sum */
2644   for (cell = 1; cell <= numCells; ++cell) {
2645     off[cell] += off[cell-1];
2646   }
2647   if (adjacency) {
2648     ierr = PetscMalloc(off[numCells] * sizeof(PetscInt), &adj);CHKERRQ(ierr);
2649     /* Get neighboring cells */
2650     for (cell = cStart; cell < cEnd; ++cell) {
2651       PetscInt numNeighbors = maxNeighbors, n;
2652       PetscInt cellOffset   = 0;
2653 
2654       ierr = DMPlexGetAdjacencySingleLevel_Private(dm, cell, PETSC_TRUE, tmpClosure, &numNeighbors, neighborCells);CHKERRQ(ierr);
2655       /* Get meet with each cell, and check with recognizer (could optimize to check each pair only once) */
2656       for (n = 0; n < numNeighbors; ++n) {
2657         PetscInt        cellPair[2] = {cell, neighborCells[n]};
2658         PetscBool       found       = depth > 1 ? PETSC_TRUE : PETSC_FALSE;
2659         PetscInt        meetSize    = 0;
2660         const PetscInt *meet        = PETSC_NULL;
2661 
2662         if (cellPair[0] == cellPair[1]) continue;
2663         if (!found) {
2664           ierr = DMPlexGetMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2665           if (meetSize) {
2666             PetscInt f;
2667 
2668             for (f = 0; f < numFaceCases; ++f) {
2669               if (numFaceVertices[f] == meetSize) {
2670                 found = PETSC_TRUE;
2671                 break;
2672               }
2673             }
2674           }
2675           ierr = DMPlexRestoreMeet(dm, 2, cellPair, &meetSize, &meet);CHKERRQ(ierr);
2676         }
2677         if (found) {
2678           adj[off[cell-cStart]+cellOffset] = neighborCells[n];
2679           ++cellOffset;
2680         }
2681       }
2682     }
2683   }
2684   ierr = PetscFree2(neighborCells,tmpClosure);CHKERRQ(ierr);
2685   if (numVertices) *numVertices = numCells;
2686   if (offsets)     *offsets     = off;
2687   if (adjacency)   *adjacency   = adj;
2688   PetscFunctionReturn(0);
2689 }
2690 
2691 #ifdef PETSC_HAVE_CHACO
2692 #ifdef PETSC_HAVE_UNISTD_H
2693 #include <unistd.h>
2694 #endif
2695 /* Chaco does not have an include file */
2696 PETSC_EXTERN_C int interface(int nvtxs, int *start, int *adjacency, int *vwgts,
2697                        float *ewgts, float *x, float *y, float *z, char *outassignname,
2698                        char *outfilename, short *assignment, int architecture, int ndims_tot,
2699                        int mesh_dims[3], double *goal, int global_method, int local_method,
2700                        int rqi_flag, int vmax, int ndims, double eigtol, long seed);
2701 
2702 extern int FREE_GRAPH;
2703 
2704 #undef __FUNCT__
2705 #define __FUNCT__ "DMPlexPartition_Chaco"
2706 PetscErrorCode DMPlexPartition_Chaco(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2707 {
2708   enum {DEFAULT_METHOD = 1, INERTIAL_METHOD = 3};
2709   MPI_Comm comm = ((PetscObject) dm)->comm;
2710   int nvtxs = numVertices;                /* number of vertices in full graph */
2711   int *vwgts = NULL;                      /* weights for all vertices */
2712   float *ewgts = NULL;                    /* weights for all edges */
2713   float *x = NULL, *y = NULL, *z = NULL;  /* coordinates for inertial method */
2714   char *outassignname = NULL;             /*  name of assignment output file */
2715   char *outfilename = NULL;               /* output file name */
2716   int architecture = 1;                   /* 0 => hypercube, d => d-dimensional mesh */
2717   int ndims_tot = 0;                      /* total number of cube dimensions to divide */
2718   int mesh_dims[3];                       /* dimensions of mesh of processors */
2719   double *goal = NULL;                    /* desired set sizes for each set */
2720   int global_method = 1;                  /* global partitioning algorithm */
2721   int local_method = 1;                   /* local partitioning algorithm */
2722   int rqi_flag = 0;                       /* should I use RQI/Symmlq eigensolver? */
2723   int vmax = 200;                         /* how many vertices to coarsen down to? */
2724   int ndims = 1;                          /* number of eigenvectors (2^d sets) */
2725   double eigtol = 0.001;                  /* tolerance on eigenvectors */
2726   long seed = 123636512;                  /* for random graph mutations */
2727   short int *assignment;                  /* Output partition */
2728   int fd_stdout, fd_pipe[2];
2729   PetscInt      *points;
2730   PetscMPIInt    commSize;
2731   int            i, v, p;
2732   PetscErrorCode ierr;
2733 
2734   PetscFunctionBegin;
2735   ierr = MPI_Comm_size(comm, &commSize);CHKERRQ(ierr);
2736   if (!numVertices) {
2737     ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2738     ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2739     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2740     ierr = ISCreateGeneral(comm, 0, PETSC_NULL, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2741     PetscFunctionReturn(0);
2742   }
2743   FREE_GRAPH = 0;                         /* Do not let Chaco free my memory */
2744   for (i = 0; i < start[numVertices]; ++i) {
2745     ++adjacency[i];
2746   }
2747   if (global_method == INERTIAL_METHOD) {
2748     /* manager.createCellCoordinates(nvtxs, &x, &y, &z); */
2749     SETERRQ(comm, PETSC_ERR_SUP, "Inertial partitioning not yet supported");
2750   }
2751   mesh_dims[0] = commSize;
2752   mesh_dims[1] = 1;
2753   mesh_dims[2] = 1;
2754   ierr = PetscMalloc(nvtxs * sizeof(short int), &assignment);CHKERRQ(ierr);
2755   /* Chaco outputs to stdout. We redirect this to a buffer. */
2756   /* TODO: check error codes for UNIX calls */
2757 #ifdef PETSC_HAVE_UNISTD_H
2758   {
2759     fd_stdout = dup(1);
2760     pipe(fd_pipe);
2761     close(1);
2762     dup2(fd_pipe[1], 1);
2763   }
2764 #endif
2765   ierr = interface(nvtxs, (int *) start, (int *) adjacency, vwgts, ewgts, x, y, z, outassignname, outfilename,
2766                    assignment, architecture, ndims_tot, mesh_dims, goal, global_method, local_method, rqi_flag,
2767                    vmax, ndims, eigtol, seed);
2768 #ifdef PETSC_HAVE_UNISTD_H
2769   {
2770     char msgLog[10000];
2771     int  count;
2772 
2773     fflush(stdout);
2774     count = read(fd_pipe[0], msgLog, (10000-1)*sizeof(char));
2775     if (count < 0) count = 0;
2776     msgLog[count] = 0;
2777     close(1);
2778     dup2(fd_stdout, 1);
2779     close(fd_stdout);
2780     close(fd_pipe[0]);
2781     close(fd_pipe[1]);
2782     if (ierr) SETERRQ1(comm, PETSC_ERR_LIB, "Error in Chaco library: %s", msgLog);
2783   }
2784 #endif
2785   /* Convert to PetscSection+IS */
2786   ierr = PetscSectionCreate(comm, partSection);CHKERRQ(ierr);
2787   ierr = PetscSectionSetChart(*partSection, 0, commSize);CHKERRQ(ierr);
2788   for (v = 0; v < nvtxs; ++v) {
2789     ierr = PetscSectionAddDof(*partSection, assignment[v], 1);CHKERRQ(ierr);
2790   }
2791   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2792   ierr = PetscMalloc(nvtxs * sizeof(PetscInt), &points);CHKERRQ(ierr);
2793   for (p = 0, i = 0; p < commSize; ++p) {
2794     for (v = 0; v < nvtxs; ++v) {
2795       if (assignment[v] == p) points[i++] = v;
2796     }
2797   }
2798   if (i != nvtxs) SETERRQ2(comm, PETSC_ERR_PLIB, "Number of points %D should be %D", i, nvtxs);
2799   ierr = ISCreateGeneral(comm, nvtxs, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2800   if (global_method == INERTIAL_METHOD) {
2801     /* manager.destroyCellCoordinates(nvtxs, &x, &y, &z); */
2802   }
2803   ierr = PetscFree(assignment);CHKERRQ(ierr);
2804   for (i = 0; i < start[numVertices]; ++i) {
2805     --adjacency[i];
2806   }
2807   PetscFunctionReturn(0);
2808 }
2809 #endif
2810 
2811 #ifdef PETSC_HAVE_PARMETIS
2812 #undef __FUNCT__
2813 #define __FUNCT__ "DMPlexPartition_ParMetis"
2814 PetscErrorCode DMPlexPartition_ParMetis(DM dm, PetscInt numVertices, PetscInt start[], PetscInt adjacency[], PetscSection *partSection, IS *partition)
2815 {
2816   PetscFunctionBegin;
2817   SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "ParMetis not yet supported");
2818   PetscFunctionReturn(0);
2819 }
2820 #endif
2821 
2822 #undef __FUNCT__
2823 #define __FUNCT__ "DMPlexEnlargePartition"
2824 /* Expand the partition by BFS on the adjacency graph */
2825 PetscErrorCode DMPlexEnlargePartition(DM dm, const PetscInt start[], const PetscInt adjacency[], PetscSection origPartSection, IS origPartition, PetscSection *partSection, IS *partition) {
2826   PetscHashI      h;
2827   const PetscInt *points;
2828   PetscInt      **tmpPoints, *newPoints, totPoints = 0;
2829   PetscInt        pStart, pEnd, part, q;
2830   PetscErrorCode  ierr;
2831 
2832   PetscFunctionBegin;
2833   PetscHashICreate(h);
2834   ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2835   ierr = PetscSectionGetChart(origPartSection, &pStart, &pEnd);CHKERRQ(ierr);
2836   ierr = PetscSectionSetChart(*partSection, pStart, pEnd);CHKERRQ(ierr);
2837   ierr = ISGetIndices(origPartition, &points);CHKERRQ(ierr);
2838   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt *), &tmpPoints);CHKERRQ(ierr);
2839   for(part = pStart; part < pEnd; ++part) {
2840     PetscInt numPoints, nP, numNewPoints, off, p, n = 0;
2841 
2842     PetscHashIClear(h);
2843     ierr = PetscSectionGetDof(origPartSection, part, &numPoints);CHKERRQ(ierr);
2844     ierr = PetscSectionGetOffset(origPartSection, part, &off);CHKERRQ(ierr);
2845     /* Add all existing points to h */
2846     for(p = 0; p < numPoints; ++p) {
2847       const PetscInt point = points[off+p];
2848       PetscHashIAdd(h, point, 1);
2849     }
2850     PetscHashISize(h, nP);
2851     if (nP != numPoints) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Invalid partition has %d points, but only %d were unique", numPoints, nP);
2852     /* Add all points in next BFS level */
2853     /*   TODO We are brute forcing here, but could check the adjacency size to find the boundary */
2854     for(p = 0; p < numPoints; ++p) {
2855       const PetscInt point = points[off+p];
2856       PetscInt s = start[point], e = start[point+1], a;
2857 
2858       for(a = s; a < e; ++a) {
2859         PetscHashIAdd(h, adjacency[a], 1);
2860       }
2861     }
2862     PetscHashISize(h, numNewPoints);
2863     ierr = PetscSectionSetDof(*partSection, part, numNewPoints);CHKERRQ(ierr);
2864     ierr = PetscMalloc(numNewPoints * sizeof(PetscInt), &tmpPoints[part]);CHKERRQ(ierr);
2865     if (numNewPoints) {PetscHashIGetKeys(h, n, tmpPoints[part]);} /* Should not need this conditional */
2866     totPoints += numNewPoints;
2867   }
2868   ierr = ISRestoreIndices(origPartition, &points);CHKERRQ(ierr);
2869   PetscHashIDestroy(h);
2870   ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2871   ierr = PetscMalloc(totPoints * sizeof(PetscInt), &newPoints);CHKERRQ(ierr);
2872   for(part = pStart, q = 0; part < pEnd; ++part) {
2873     PetscInt numPoints, p;
2874 
2875     ierr = PetscSectionGetDof(*partSection, part, &numPoints);CHKERRQ(ierr);
2876     for(p = 0; p < numPoints; ++p, ++q) {
2877       newPoints[q] = tmpPoints[part][p];
2878     }
2879     ierr = PetscFree(tmpPoints[part]);CHKERRQ(ierr);
2880   }
2881   ierr = PetscFree(tmpPoints);CHKERRQ(ierr);
2882   ierr = ISCreateGeneral(((PetscObject) dm)->comm, totPoints, newPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2883   PetscFunctionReturn(0);
2884 }
2885 
2886 #undef __FUNCT__
2887 #define __FUNCT__ "DMPlexCreatePartition"
2888 /*
2889   DMPlexCreatePartition - Create a non-overlapping partition of the points at the given height
2890 
2891   Collective on DM
2892 
2893   Input Parameters:
2894   + dm - The DM
2895   . height - The height for points in the partition
2896   - enlarge - Expand each partition with neighbors
2897 
2898   Output Parameters:
2899   + partSection - The PetscSection giving the division of points by partition
2900   . partition - The list of points by partition
2901   . origPartSection - If enlarge is true, the PetscSection giving the division of points before enlarging by partition, otherwise PETSC_NULL
2902   - origPartition - If enlarge is true, the list of points before enlarging by partition, otherwise PETSC_NULL
2903 
2904   Level: developer
2905 
2906 .seealso DMPlexDistribute()
2907 */
2908 PetscErrorCode DMPlexCreatePartition(DM dm, PetscInt height, PetscBool enlarge, PetscSection *partSection, IS *partition, PetscSection *origPartSection, IS *origPartition) {
2909   PetscMPIInt    size;
2910   PetscErrorCode ierr;
2911 
2912   PetscFunctionBegin;
2913   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &size);CHKERRQ(ierr);
2914   *origPartSection = PETSC_NULL;
2915   *origPartition   = PETSC_NULL;
2916   if (size == 1) {
2917     PetscInt *points;
2918     PetscInt  cStart, cEnd, c;
2919 
2920     ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
2921     ierr = PetscSectionCreate(((PetscObject) dm)->comm, partSection);CHKERRQ(ierr);
2922     ierr = PetscSectionSetChart(*partSection, 0, size);CHKERRQ(ierr);
2923     ierr = PetscSectionSetDof(*partSection, 0, cEnd-cStart);CHKERRQ(ierr);
2924     ierr = PetscSectionSetUp(*partSection);CHKERRQ(ierr);
2925     ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscInt), &points);CHKERRQ(ierr);
2926     for (c = cStart; c < cEnd; ++c) {
2927       points[c] = c;
2928     }
2929     ierr = ISCreateGeneral(((PetscObject) dm)->comm, cEnd-cStart, points, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
2930     PetscFunctionReturn(0);
2931   }
2932   if (height == 0) {
2933     PetscInt  numVertices;
2934     PetscInt *start     = PETSC_NULL;
2935     PetscInt *adjacency = PETSC_NULL;
2936 
2937     ierr = DMPlexCreateNeighborCSR(dm, &numVertices, &start, &adjacency);CHKERRQ(ierr);
2938     if (1) {
2939 #ifdef PETSC_HAVE_CHACO
2940       ierr = DMPlexPartition_Chaco(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2941 #endif
2942     } else {
2943 #ifdef PETSC_HAVE_PARMETIS
2944       ierr = DMPlexPartition_ParMetis(dm, numVertices, start, adjacency, partSection, partition);CHKERRQ(ierr);
2945 #endif
2946     }
2947     if (enlarge) {
2948       *origPartSection = *partSection;
2949       *origPartition   = *partition;
2950       ierr = DMPlexEnlargePartition(dm, start, adjacency, *origPartSection, *origPartition, partSection, partition);CHKERRQ(ierr);
2951     }
2952     ierr = PetscFree(start);CHKERRQ(ierr);
2953     ierr = PetscFree(adjacency);CHKERRQ(ierr);
2954 # if 0
2955   } else if (height == 1) {
2956     /* Build the dual graph for faces and partition the hypergraph */
2957     PetscInt numEdges;
2958 
2959     buildFaceCSRV(mesh, mesh->getFactory()->getNumbering(mesh, mesh->depth()-1), &numEdges, &start, &adjacency, GraphPartitioner::zeroBase());
2960     GraphPartitioner().partition(numEdges, start, adjacency, partition, manager);
2961     destroyCSR(numEdges, start, adjacency);
2962 #endif
2963   } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid partition height %D", height);
2964   PetscFunctionReturn(0);
2965 }
2966 
2967 #undef __FUNCT__
2968 #define __FUNCT__ "DMPlexCreatePartitionClosure"
2969 PetscErrorCode DMPlexCreatePartitionClosure(DM dm, PetscSection pointSection, IS pointPartition, PetscSection *section, IS *partition) {
2970   /* const PetscInt  height = 0; */
2971   const PetscInt *partArray;
2972   PetscInt       *allPoints, *partPoints = PETSC_NULL;
2973   PetscInt        rStart, rEnd, rank, maxPartSize = 0, newSize;
2974   PetscErrorCode  ierr;
2975 
2976   PetscFunctionBegin;
2977   ierr = PetscSectionGetChart(pointSection, &rStart, &rEnd);CHKERRQ(ierr);
2978   ierr = ISGetIndices(pointPartition, &partArray);CHKERRQ(ierr);
2979   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
2980   ierr = PetscSectionSetChart(*section, rStart, rEnd);CHKERRQ(ierr);
2981   for (rank = rStart; rank < rEnd; ++rank) {
2982     PetscInt partSize = 0;
2983     PetscInt numPoints, offset, p;
2984 
2985     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
2986     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
2987     for (p = 0; p < numPoints; ++p) {
2988       PetscInt  point   = partArray[offset+p], closureSize, c;
2989       PetscInt *closure = PETSC_NULL;
2990 
2991       /* TODO Include support for height > 0 case */
2992       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
2993       /* Merge into existing points */
2994       if (partSize+closureSize > maxPartSize) {
2995         PetscInt *tmpPoints;
2996 
2997         maxPartSize = PetscMax(partSize+closureSize, 2*maxPartSize);
2998         ierr = PetscMalloc(maxPartSize * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
2999         ierr = PetscMemcpy(tmpPoints, partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3000         ierr = PetscFree(partPoints);CHKERRQ(ierr);
3001         partPoints = tmpPoints;
3002       }
3003       for (c = 0; c < closureSize; ++c) {
3004         partPoints[partSize+c] = closure[c*2];
3005       }
3006       partSize += closureSize;
3007       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3008       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3009     }
3010     ierr = PetscSectionSetDof(*section, rank, partSize);CHKERRQ(ierr);
3011   }
3012   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
3013   ierr = PetscSectionGetStorageSize(*section, &newSize);CHKERRQ(ierr);
3014   ierr = PetscMalloc(newSize * sizeof(PetscInt), &allPoints);CHKERRQ(ierr);
3015 
3016   for (rank = rStart; rank < rEnd; ++rank) {
3017     PetscInt partSize = 0, newOffset;
3018     PetscInt numPoints, offset, p;
3019 
3020     ierr = PetscSectionGetDof(pointSection, rank, &numPoints);CHKERRQ(ierr);
3021     ierr = PetscSectionGetOffset(pointSection, rank, &offset);CHKERRQ(ierr);
3022     for (p = 0; p < numPoints; ++p) {
3023       PetscInt  point   = partArray[offset+p], closureSize, c;
3024       PetscInt *closure = PETSC_NULL;
3025 
3026       /* TODO Include support for height > 0 case */
3027       ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3028       /* Merge into existing points */
3029       for (c = 0; c < closureSize; ++c) {
3030         partPoints[partSize+c] = closure[c*2];
3031       }
3032       partSize += closureSize;
3033       ierr = PetscSortRemoveDupsInt(&partSize, partPoints);CHKERRQ(ierr);
3034       ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
3035     }
3036     ierr = PetscSectionGetOffset(*section, rank, &newOffset);CHKERRQ(ierr);
3037     ierr = PetscMemcpy(&allPoints[newOffset], partPoints, partSize * sizeof(PetscInt));CHKERRQ(ierr);
3038   }
3039   ierr = ISRestoreIndices(pointPartition, &partArray);CHKERRQ(ierr);
3040   ierr = PetscFree(partPoints);CHKERRQ(ierr);
3041   ierr = ISCreateGeneral(((PetscObject) dm)->comm, newSize, allPoints, PETSC_OWN_POINTER, partition);CHKERRQ(ierr);
3042   PetscFunctionReturn(0);
3043 }
3044 
3045 #undef __FUNCT__
3046 #define __FUNCT__ "DMPlexDistributeField"
3047 /*
3048   Input Parameters:
3049 . originalSection
3050 , originalVec
3051 
3052   Output Parameters:
3053 . newSection
3054 . newVec
3055 */
3056 PetscErrorCode DMPlexDistributeField(DM dm, PetscSF pointSF, PetscSection originalSection, Vec originalVec, PetscSection newSection, Vec newVec)
3057 {
3058   PetscSF         fieldSF;
3059   PetscInt       *remoteOffsets, fieldSize;
3060   PetscScalar    *originalValues, *newValues;
3061   PetscErrorCode  ierr;
3062 
3063   PetscFunctionBegin;
3064   ierr = PetscSFDistributeSection(pointSF, originalSection, &remoteOffsets, newSection);CHKERRQ(ierr);
3065 
3066   ierr = PetscSectionGetStorageSize(newSection, &fieldSize);CHKERRQ(ierr);
3067   ierr = VecSetSizes(newVec, fieldSize, PETSC_DETERMINE);CHKERRQ(ierr);
3068   ierr = VecSetFromOptions(newVec);CHKERRQ(ierr);
3069 
3070   ierr = VecGetArray(originalVec, &originalValues);CHKERRQ(ierr);
3071   ierr = VecGetArray(newVec, &newValues);CHKERRQ(ierr);
3072   ierr = PetscSFCreateSectionSF(pointSF, originalSection, remoteOffsets, newSection, &fieldSF);CHKERRQ(ierr);
3073   ierr = PetscSFBcastBegin(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3074   ierr = PetscSFBcastEnd(fieldSF, MPIU_SCALAR, originalValues, newValues);CHKERRQ(ierr);
3075   ierr = PetscSFDestroy(&fieldSF);CHKERRQ(ierr);
3076   ierr = VecRestoreArray(newVec, &newValues);CHKERRQ(ierr);
3077   ierr = VecRestoreArray(originalVec, &originalValues);CHKERRQ(ierr);
3078   PetscFunctionReturn(0);
3079 }
3080 
3081 #undef __FUNCT__
3082 #define __FUNCT__ "DMPlexDistribute"
3083 /*@C
3084   DMPlexDistribute - Distributes the mesh and any associated sections.
3085 
3086   Not Collective
3087 
3088   Input Parameter:
3089 + dm  - The original DMPlex object
3090 . partitioner - The partitioning package, or NULL for the default
3091 - overlap - The overlap of partitions, 0 is the default
3092 
3093   Output Parameter:
3094 . parallelMesh - The distributed DMPlex object, or PETSC_NULL
3095 
3096   Note: If the mesh was not distributed, the return value is PETSC_NULL
3097 
3098   Level: intermediate
3099 
3100 .keywords: mesh, elements
3101 .seealso: DMPlexCreate(), DMPlexDistributeByFace()
3102 @*/
3103 PetscErrorCode DMPlexDistribute(DM dm, const char partitioner[], PetscInt overlap, DM *dmParallel)
3104 {
3105   DM_Plex    *mesh   = (DM_Plex *) dm->data, *pmesh;
3106   MPI_Comm       comm   = ((PetscObject) dm)->comm;
3107   const PetscInt height = 0;
3108   PetscInt       dim, numRemoteRanks;
3109   IS             origCellPart,        cellPart,        part;
3110   PetscSection   origCellPartSection, cellPartSection, partSection;
3111   PetscSFNode   *remoteRanks;
3112   PetscSF        partSF, pointSF, coneSF;
3113   ISLocalToGlobalMapping renumbering;
3114   PetscSection   originalConeSection, newConeSection;
3115   PetscInt      *remoteOffsets;
3116   PetscInt      *cones, *newCones, newConesSize;
3117   PetscBool      flg;
3118   PetscMPIInt    rank, numProcs, p;
3119   PetscErrorCode ierr;
3120 
3121   PetscFunctionBegin;
3122   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3123   PetscValidPointer(dmParallel,4);
3124   ierr = PetscLogEventBegin(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3125   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
3126   ierr = MPI_Comm_size(comm, &numProcs);CHKERRQ(ierr);
3127   *dmParallel = PETSC_NULL;
3128   if (numProcs == 1) PetscFunctionReturn(0);
3129 
3130   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3131   /* Create cell partition - We need to rewrite to use IS, use the MatPartition stuff */
3132   if (overlap > 1) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Overlap > 1 not yet implemented");
3133   ierr = DMPlexCreatePartition(dm, height, overlap > 0 ? PETSC_TRUE : PETSC_FALSE, &cellPartSection, &cellPart, &origCellPartSection, &origCellPart);CHKERRQ(ierr);
3134   /* Create SF assuming a serial partition for all processes: Could check for IS length here */
3135   if (!rank) {
3136     numRemoteRanks = numProcs;
3137   } else {
3138     numRemoteRanks = 0;
3139   }
3140   ierr = PetscMalloc(numRemoteRanks * sizeof(PetscSFNode), &remoteRanks);CHKERRQ(ierr);
3141   for (p = 0; p < numRemoteRanks; ++p) {
3142     remoteRanks[p].rank  = p;
3143     remoteRanks[p].index = 0;
3144   }
3145   ierr = PetscSFCreate(comm, &partSF);CHKERRQ(ierr);
3146   ierr = PetscSFSetGraph(partSF, 1, numRemoteRanks, PETSC_NULL, PETSC_OWN_POINTER, remoteRanks, PETSC_OWN_POINTER);CHKERRQ(ierr);
3147   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-partition_view", &flg);CHKERRQ(ierr);
3148   if (flg) {
3149     ierr = PetscPrintf(comm, "Cell Partition:\n");CHKERRQ(ierr);
3150     ierr = PetscSectionView(cellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3151     ierr = ISView(cellPart, PETSC_NULL);CHKERRQ(ierr);
3152     if (origCellPart) {
3153       ierr = PetscPrintf(comm, "Original Cell Partition:\n");CHKERRQ(ierr);
3154       ierr = PetscSectionView(origCellPartSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3155       ierr = ISView(origCellPart, PETSC_NULL);CHKERRQ(ierr);
3156     }
3157     ierr = PetscSFView(partSF, PETSC_NULL);CHKERRQ(ierr);
3158   }
3159   /* Close the partition over the mesh */
3160   ierr = DMPlexCreatePartitionClosure(dm, cellPartSection, cellPart, &partSection, &part);CHKERRQ(ierr);
3161   ierr = ISDestroy(&cellPart);CHKERRQ(ierr);
3162   ierr = PetscSectionDestroy(&cellPartSection);CHKERRQ(ierr);
3163   /* Create new mesh */
3164   ierr = DMPlexCreate(comm, dmParallel);CHKERRQ(ierr);
3165   ierr = DMPlexSetDimension(*dmParallel, dim);CHKERRQ(ierr);
3166   ierr = PetscObjectSetName((PetscObject) *dmParallel, "Parallel Mesh");CHKERRQ(ierr);
3167   pmesh = (DM_Plex *) (*dmParallel)->data;
3168   /* Distribute sieve points and the global point numbering (replaces creating remote bases) */
3169   ierr = PetscSFConvertPartition(partSF, partSection, part, &renumbering, &pointSF);CHKERRQ(ierr);
3170   if (flg) {
3171     ierr = PetscPrintf(comm, "Point Partition:\n");CHKERRQ(ierr);
3172     ierr = PetscSectionView(partSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3173     ierr = ISView(part, PETSC_NULL);CHKERRQ(ierr);
3174     ierr = PetscSFView(pointSF, PETSC_NULL);CHKERRQ(ierr);
3175     ierr = PetscPrintf(comm, "Point Renumbering after partition:\n");CHKERRQ(ierr);
3176     ierr = ISLocalToGlobalMappingView(renumbering, PETSC_NULL);CHKERRQ(ierr);
3177   }
3178   /* Distribute cone section */
3179   ierr = DMPlexGetConeSection(dm, &originalConeSection);CHKERRQ(ierr);
3180   ierr = DMPlexGetConeSection(*dmParallel, &newConeSection);CHKERRQ(ierr);
3181   ierr = PetscSFDistributeSection(pointSF, originalConeSection, &remoteOffsets, newConeSection);CHKERRQ(ierr);
3182   ierr = DMSetUp(*dmParallel);CHKERRQ(ierr);
3183   {
3184     PetscInt pStart, pEnd, p;
3185 
3186     ierr = PetscSectionGetChart(newConeSection, &pStart, &pEnd);CHKERRQ(ierr);
3187     for (p = pStart; p < pEnd; ++p) {
3188       PetscInt coneSize;
3189       ierr = PetscSectionGetDof(newConeSection, p, &coneSize);CHKERRQ(ierr);
3190       pmesh->maxConeSize = PetscMax(pmesh->maxConeSize, coneSize);
3191     }
3192   }
3193   /* Communicate and renumber cones */
3194   ierr = PetscSFCreateSectionSF(pointSF, originalConeSection, remoteOffsets, newConeSection, &coneSF);CHKERRQ(ierr);
3195   ierr = DMPlexGetCones(dm, &cones);CHKERRQ(ierr);
3196   ierr = DMPlexGetCones(*dmParallel, &newCones);CHKERRQ(ierr);
3197   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3198   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3199   ierr = PetscSectionGetStorageSize(newConeSection, &newConesSize);CHKERRQ(ierr);
3200   ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newConesSize, newCones, PETSC_NULL, newCones);CHKERRQ(ierr);
3201   ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-cones_view", &flg);CHKERRQ(ierr);
3202   if (flg) {
3203     ierr = PetscPrintf(comm, "Serial Cone Section:\n");CHKERRQ(ierr);
3204     ierr = PetscSectionView(originalConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3205     ierr = PetscPrintf(comm, "Parallel Cone Section:\n");CHKERRQ(ierr);
3206     ierr = PetscSectionView(newConeSection, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3207     ierr = PetscSFView(coneSF, PETSC_NULL);CHKERRQ(ierr);
3208   }
3209   ierr = DMPlexGetConeOrientations(dm, &cones);CHKERRQ(ierr);
3210   ierr = DMPlexGetConeOrientations(*dmParallel, &newCones);CHKERRQ(ierr);
3211   ierr = PetscSFBcastBegin(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3212   ierr = PetscSFBcastEnd(coneSF, MPIU_INT, cones, newCones);CHKERRQ(ierr);
3213   ierr = PetscSFDestroy(&coneSF);CHKERRQ(ierr);
3214   /* Create supports and stratify sieve */
3215   {
3216     PetscInt pStart, pEnd;
3217 
3218     ierr = PetscSectionGetChart(pmesh->coneSection, &pStart, &pEnd);CHKERRQ(ierr);
3219     ierr = PetscSectionSetChart(pmesh->supportSection, pStart, pEnd);CHKERRQ(ierr);
3220   }
3221   ierr = DMPlexSymmetrize(*dmParallel);CHKERRQ(ierr);
3222   ierr = DMPlexStratify(*dmParallel);CHKERRQ(ierr);
3223   /* Distribute Coordinates */
3224   {
3225     PetscSection originalCoordSection, newCoordSection;
3226     Vec          originalCoordinates, newCoordinates;
3227     const char  *name;
3228 
3229     ierr = DMPlexGetCoordinateSection(dm, &originalCoordSection);CHKERRQ(ierr);
3230     ierr = DMPlexGetCoordinateSection(*dmParallel, &newCoordSection);CHKERRQ(ierr);
3231     ierr = DMGetCoordinatesLocal(dm, &originalCoordinates);CHKERRQ(ierr);
3232     ierr = VecCreate(comm, &newCoordinates);CHKERRQ(ierr);
3233     ierr = PetscObjectGetName((PetscObject) originalCoordinates, &name);CHKERRQ(ierr);
3234     ierr = PetscObjectSetName((PetscObject) newCoordinates, name);CHKERRQ(ierr);
3235 
3236     ierr = DMPlexDistributeField(dm, pointSF, originalCoordSection, originalCoordinates, newCoordSection, newCoordinates);CHKERRQ(ierr);
3237     ierr = DMSetCoordinatesLocal(*dmParallel, newCoordinates);CHKERRQ(ierr);
3238     ierr = VecDestroy(&newCoordinates);CHKERRQ(ierr);
3239   }
3240   /* Distribute labels */
3241   {
3242     DMLabel    next      = mesh->labels, newNext = pmesh->labels;
3243     PetscInt   numLabels = 0, l;
3244 
3245     /* Bcast number of labels */
3246     while(next) {++numLabels; next = next->next;}
3247     ierr = MPI_Bcast(&numLabels, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3248     next = mesh->labels;
3249     for (l = 0; l < numLabels; ++l) {
3250       DMLabel         newLabel;
3251       const PetscInt *partArray;
3252       char           *name;
3253       PetscInt       *stratumSizes = PETSC_NULL, *points = PETSC_NULL;
3254       PetscMPIInt    *sendcnts = PETSC_NULL, *offsets = PETSC_NULL, *displs = PETSC_NULL;
3255       PetscInt        nameSize, s, p;
3256       PetscBool       isdepth;
3257       size_t          len = 0;
3258 
3259       /* Bcast name (could filter for no points) */
3260       if (!rank) {ierr = PetscStrlen(next->name, &len);CHKERRQ(ierr);}
3261       nameSize = len;
3262       ierr = MPI_Bcast(&nameSize, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3263       ierr = PetscMalloc(nameSize+1, &name);CHKERRQ(ierr);
3264       if (!rank) {ierr = PetscMemcpy(name, next->name, nameSize+1);CHKERRQ(ierr);}
3265       ierr = MPI_Bcast(name, nameSize+1, MPI_CHAR, 0, comm);CHKERRQ(ierr);
3266       ierr = PetscStrcmp(name, "depth", &isdepth);CHKERRQ(ierr);
3267       if (isdepth) {ierr = PetscFree(name);CHKERRQ(ierr); continue;}
3268       ierr = PetscNew(struct _n_DMLabel, &newLabel);CHKERRQ(ierr);
3269       newLabel->name = name;
3270       /* Bcast numStrata (could filter for no points in stratum) */
3271       if (!rank) {newLabel->numStrata = next->numStrata;}
3272       ierr = MPI_Bcast(&newLabel->numStrata, 1, MPIU_INT, 0, comm);CHKERRQ(ierr);
3273       ierr = PetscMalloc3(newLabel->numStrata,PetscInt,&newLabel->stratumValues,
3274                           newLabel->numStrata,PetscInt,&newLabel->stratumSizes,
3275                           newLabel->numStrata+1,PetscInt,&newLabel->stratumOffsets);CHKERRQ(ierr);
3276       /* Bcast stratumValues (could filter for no points in stratum) */
3277       if (!rank) {ierr = PetscMemcpy(newLabel->stratumValues, next->stratumValues, next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);}
3278       ierr = MPI_Bcast(newLabel->stratumValues, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3279       /* Find size on each process and Scatter */
3280       if (!rank) {
3281         ierr = ISGetIndices(part, &partArray);CHKERRQ(ierr);
3282         ierr = PetscMalloc(numProcs*next->numStrata * sizeof(PetscInt), &stratumSizes);CHKERRQ(ierr);
3283         ierr = PetscMemzero(stratumSizes, numProcs*next->numStrata * sizeof(PetscInt));CHKERRQ(ierr);
3284         for (s = 0; s < next->numStrata; ++s) {
3285           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3286             const PetscInt point = next->points[p];
3287             PetscInt       proc;
3288 
3289             for (proc = 0; proc < numProcs; ++proc) {
3290               PetscInt dof, off, pPart;
3291 
3292               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3293               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3294               for (pPart = off; pPart < off+dof; ++pPart) {
3295                 if (partArray[pPart] == point) {
3296                   ++stratumSizes[proc*next->numStrata+s];
3297                   break;
3298                 }
3299               }
3300             }
3301           }
3302         }
3303         ierr = ISRestoreIndices(part, &partArray);CHKERRQ(ierr);
3304       }
3305       ierr = MPI_Scatter(stratumSizes, newLabel->numStrata, MPIU_INT, newLabel->stratumSizes, newLabel->numStrata, MPIU_INT, 0, comm);CHKERRQ(ierr);
3306       /* Calculate stratumOffsets */
3307       newLabel->stratumOffsets[0] = 0;
3308       for (s = 0; s < newLabel->numStrata; ++s) {
3309         newLabel->stratumOffsets[s+1] = newLabel->stratumSizes[s] + newLabel->stratumOffsets[s];
3310       }
3311       /* Pack points and Scatter */
3312       if (!rank) {
3313         ierr = PetscMalloc3(numProcs,PetscMPIInt,&sendcnts,numProcs,PetscMPIInt,&offsets,numProcs+1,PetscMPIInt,&displs);CHKERRQ(ierr);
3314         displs[0] = 0;
3315         for (p = 0; p < numProcs; ++p) {
3316           sendcnts[p] = 0;
3317           for (s = 0; s < next->numStrata; ++s) {
3318             sendcnts[p] += stratumSizes[p*next->numStrata+s];
3319           }
3320           offsets[p]  = displs[p];
3321           displs[p+1] = displs[p] + sendcnts[p];
3322         }
3323         ierr = PetscMalloc(displs[numProcs] * sizeof(PetscInt), &points);CHKERRQ(ierr);
3324         for (s = 0; s < next->numStrata; ++s) {
3325           for (p = next->stratumOffsets[s]; p < next->stratumOffsets[s]+next->stratumSizes[s]; ++p) {
3326             const PetscInt point = next->points[p];
3327             PetscInt       proc;
3328 
3329             for (proc = 0; proc < numProcs; ++proc) {
3330               PetscInt dof, off, pPart;
3331 
3332               ierr = PetscSectionGetDof(partSection, proc, &dof);CHKERRQ(ierr);
3333               ierr = PetscSectionGetOffset(partSection, proc, &off);CHKERRQ(ierr);
3334               for (pPart = off; pPart < off+dof; ++pPart) {
3335                 if (partArray[pPart] == point) {
3336                   points[offsets[proc]++] = point;
3337                   break;
3338                 }
3339               }
3340             }
3341           }
3342         }
3343       }
3344       ierr = PetscMalloc(newLabel->stratumOffsets[newLabel->numStrata] * sizeof(PetscInt), &newLabel->points);CHKERRQ(ierr);
3345       ierr = MPI_Scatterv(points, sendcnts, displs, MPIU_INT, newLabel->points, newLabel->stratumOffsets[newLabel->numStrata], MPIU_INT, 0, comm);CHKERRQ(ierr);
3346       ierr = PetscFree(points);CHKERRQ(ierr);
3347       ierr = PetscFree3(sendcnts,offsets,displs);CHKERRQ(ierr);
3348       ierr = PetscFree(stratumSizes);CHKERRQ(ierr);
3349       /* Renumber points */
3350       ierr = ISGlobalToLocalMappingApply(renumbering, IS_GTOLM_MASK, newLabel->stratumOffsets[newLabel->numStrata], newLabel->points, PETSC_NULL, newLabel->points);CHKERRQ(ierr);
3351       /* Sort points */
3352       for (s = 0; s < newLabel->numStrata; ++s) {
3353         ierr = PetscSortInt(newLabel->stratumSizes[s], &newLabel->points[newLabel->stratumOffsets[s]]);CHKERRQ(ierr);
3354       }
3355       /* Insert into list */
3356       if (newNext) {
3357         newNext->next = newLabel;
3358       } else {
3359         pmesh->labels = newLabel;
3360       }
3361       newNext = newLabel;
3362       if (!rank) {next = next->next;}
3363     }
3364   }
3365   /* Cleanup Partition */
3366   ierr = ISLocalToGlobalMappingDestroy(&renumbering);CHKERRQ(ierr);
3367   ierr = PetscSFDestroy(&partSF);CHKERRQ(ierr);
3368   ierr = PetscSectionDestroy(&partSection);CHKERRQ(ierr);
3369   ierr = ISDestroy(&part);CHKERRQ(ierr);
3370   /* Create point SF for parallel mesh */
3371   {
3372     const PetscInt *leaves;
3373     PetscSFNode    *remotePoints, *rowners, *lowners;
3374     PetscInt        numRoots, numLeaves, numGhostPoints = 0, p, gp, *ghostPoints;
3375     PetscInt        pStart, pEnd;
3376 
3377     ierr = DMPlexGetChart(*dmParallel, &pStart, &pEnd);CHKERRQ(ierr);
3378     ierr = PetscSFGetGraph(pointSF, &numRoots, &numLeaves, &leaves, PETSC_NULL);CHKERRQ(ierr);
3379     ierr = PetscMalloc2(numRoots,PetscSFNode,&rowners,numLeaves,PetscSFNode,&lowners);CHKERRQ(ierr);
3380     for (p=0; p<numRoots; p++) {
3381       rowners[p].rank = -1;
3382       rowners[p].index = -1;
3383     }
3384     if (origCellPart) {
3385       /* Make sure cells in the original partition are not assigned to other procs */
3386       const PetscInt *origCells;
3387 
3388       ierr = ISGetIndices(origCellPart, &origCells);CHKERRQ(ierr);
3389       for (p = 0; p < numProcs; ++p) {
3390         PetscInt dof, off, d;
3391 
3392         ierr = PetscSectionGetDof(origCellPartSection, p, &dof);CHKERRQ(ierr);
3393         ierr = PetscSectionGetOffset(origCellPartSection, p, &off);CHKERRQ(ierr);
3394         for(d = off; d < off+dof; ++d) {
3395           rowners[origCells[d]].rank = p;
3396         }
3397       }
3398       ierr = ISRestoreIndices(origCellPart, &origCells);CHKERRQ(ierr);
3399     }
3400     ierr = ISDestroy(&origCellPart);CHKERRQ(ierr);
3401     ierr = PetscSectionDestroy(&origCellPartSection);CHKERRQ(ierr);
3402 
3403     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3404     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3405     for (p = 0; p < numLeaves; ++p) {
3406       if (lowners[p].rank < 0 || lowners[p].rank == rank) { /* Either put in a bid or we know we own it */
3407         lowners[p].rank = rank;
3408         lowners[p].index = leaves ? leaves[p] : p;
3409       } else if (lowners[p].rank >= 0) { /* Point already claimed so flag so that MAXLOC does not listen to us */
3410         lowners[p].rank = -2;
3411         lowners[p].index = -2;
3412       }
3413     }
3414     for (p=0; p<numRoots; p++) { /* Root must not participate in the rediction, flag so that MAXLOC does not use */
3415       rowners[p].rank = -3;
3416       rowners[p].index = -3;
3417     }
3418     ierr = PetscSFReduceBegin(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3419     ierr = PetscSFReduceEnd(pointSF, MPIU_2INT, lowners, rowners, MPI_MAXLOC);CHKERRQ(ierr);
3420     ierr = PetscSFBcastBegin(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3421     ierr = PetscSFBcastEnd(pointSF, MPIU_2INT, rowners, lowners);CHKERRQ(ierr);
3422     for (p = 0; p < numLeaves; ++p) {
3423       if (lowners[p].rank < 0 || lowners[p].index < 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Cell partition corrupt: point not claimed");
3424       if (lowners[p].rank != rank) ++numGhostPoints;
3425     }
3426     ierr = PetscMalloc(numGhostPoints * sizeof(PetscInt),    &ghostPoints);CHKERRQ(ierr);
3427     ierr = PetscMalloc(numGhostPoints * sizeof(PetscSFNode), &remotePoints);CHKERRQ(ierr);
3428     for (p = 0, gp = 0; p < numLeaves; ++p) {
3429       if (lowners[p].rank != rank) {
3430         ghostPoints[gp]       = leaves ? leaves[p] : p;
3431         remotePoints[gp].rank  = lowners[p].rank;
3432         remotePoints[gp].index = lowners[p].index;
3433         ++gp;
3434       }
3435     }
3436     ierr = PetscFree2(rowners,lowners);CHKERRQ(ierr);
3437     ierr = PetscSFSetGraph((*dmParallel)->sf, pEnd - pStart, numGhostPoints, ghostPoints, PETSC_OWN_POINTER, remotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3438     ierr = PetscSFSetFromOptions((*dmParallel)->sf);CHKERRQ(ierr);
3439   }
3440   /* Cleanup */
3441   ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
3442   ierr = DMSetFromOptions(*dmParallel);CHKERRQ(ierr);
3443   ierr = PetscLogEventEnd(DMPLEX_Distribute,dm,0,0,0);CHKERRQ(ierr);
3444   PetscFunctionReturn(0);
3445 }
3446 
3447 #undef __FUNCT__
3448 #define __FUNCT__ "DMPlexRenumber_Private"
3449 /*
3450   Reasons to renumber:
3451 
3452   1) Permute points, e.g. bandwidth reduction (Renumber)
3453 
3454     a) Must not mix strata
3455 
3456   2) Shift numbers for point insertion (Shift)
3457 
3458     a) Want operation brken into parts so that insertion can be interleaved
3459 
3460   renumbering - An IS which provides the new numbering
3461 */
3462 PetscErrorCode DMPlexRenumber_Private(DM dm, IS renumbering)
3463 {
3464   PetscFunctionBegin;
3465   PetscFunctionReturn(0);
3466 }
3467 
3468 #undef __FUNCT__
3469 #define __FUNCT__ "DMPlexShiftPoint_Private"
3470 PETSC_STATIC_INLINE PetscInt DMPlexShiftPoint_Private(PetscInt p, PetscInt depth, PetscInt depthEnd[], PetscInt depthShift[])
3471 {
3472   if (depth < 0) return p;
3473   /* Cells    */ if (p < depthEnd[depth])   return p;
3474   /* Vertices */ if (p < depthEnd[0])       return p + depthShift[depth];
3475   /* Faces    */ if (p < depthEnd[depth-1]) return p + depthShift[depth] + depthShift[0];
3476   /* Edges    */                            return p + depthShift[depth] + depthShift[0] + depthShift[depth-1];
3477 }
3478 
3479 #undef __FUNCT__
3480 #define __FUNCT__ "DMPlexShiftSizes_Private"
3481 PetscErrorCode DMPlexShiftSizes_Private(DM dm, PetscInt depthShift[], DM dmNew)
3482 {
3483   PetscInt      *depthEnd;
3484   PetscInt       depth = 0, d, pStart, pEnd, p;
3485   PetscErrorCode ierr;
3486 
3487   PetscFunctionBegin;
3488   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3489   if (depth < 0) PetscFunctionReturn(0);
3490   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3491   /* Step 1: Expand chart */
3492   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3493   for(d = 0; d <= depth; ++d) {
3494     pEnd += depthShift[d];
3495     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3496   }
3497   ierr = DMPlexSetChart(dmNew, pStart, pEnd);CHKERRQ(ierr);
3498   /* Step 2: Set cone and support sizes */
3499   for(d = 0; d <= depth; ++d) {
3500     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
3501     for(p = pStart; p < pEnd; ++p) {
3502       PetscInt newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3503       PetscInt size;
3504 
3505       ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3506       ierr = DMPlexSetConeSize(dmNew, newp, size);CHKERRQ(ierr);
3507       ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3508       ierr = DMPlexSetSupportSize(dmNew, newp, size);CHKERRQ(ierr);
3509     }
3510   }
3511   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3512   PetscFunctionReturn(0);
3513 }
3514 
3515 #undef __FUNCT__
3516 #define __FUNCT__ "DMPlexShiftPoints_Private"
3517 PetscErrorCode DMPlexShiftPoints_Private(DM dm, PetscInt depthShift[], DM dmNew)
3518 {
3519   PetscInt      *depthEnd, *newpoints;
3520   PetscInt       depth = 0, d, maxConeSize, maxSupportSize, pStart, pEnd, p;
3521   PetscErrorCode ierr;
3522 
3523   PetscFunctionBegin;
3524   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3525   if (depth < 0) PetscFunctionReturn(0);
3526   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, &maxSupportSize);CHKERRQ(ierr);
3527   ierr = PetscMalloc2(depth+1,PetscInt,&depthEnd,PetscMax(maxConeSize, maxSupportSize),PetscInt,&newpoints);CHKERRQ(ierr);
3528   for(d = 0; d <= depth; ++d) {
3529     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3530   }
3531   /* Step 5: Set cones and supports */
3532   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3533   for(p = pStart; p < pEnd; ++p) {
3534     const PetscInt *points = PETSC_NULL, *orientations = PETSC_NULL;
3535     PetscInt        size, i, newp = DMPlexShiftPoint_Private(p, depth, depthEnd, depthShift);
3536 
3537     ierr = DMPlexGetConeSize(dm, p, &size);CHKERRQ(ierr);
3538     ierr = DMPlexGetCone(dm, p, &points);CHKERRQ(ierr);
3539     ierr = DMPlexGetConeOrientation(dm, p, &orientations);CHKERRQ(ierr);
3540     for(i = 0; i < size; ++i) {
3541       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3542     }
3543     ierr = DMPlexSetCone(dmNew, newp, newpoints);CHKERRQ(ierr);
3544     ierr = DMPlexSetConeOrientation(dmNew, newp, orientations);CHKERRQ(ierr);
3545     ierr = DMPlexGetSupportSize(dm, p, &size);CHKERRQ(ierr);
3546     ierr = DMPlexGetSupport(dm, p, &points);CHKERRQ(ierr);
3547     for(i = 0; i < size; ++i) {
3548       newpoints[i] = DMPlexShiftPoint_Private(points[i], depth, depthEnd, depthShift);
3549     }
3550     ierr = DMPlexSetSupport(dmNew, newp, newpoints);CHKERRQ(ierr);
3551   }
3552   ierr = PetscFree2(depthEnd,newpoints);CHKERRQ(ierr);
3553   PetscFunctionReturn(0);
3554 }
3555 
3556 #undef __FUNCT__
3557 #define __FUNCT__ "DMPlexShiftCoordinates_Private"
3558 PetscErrorCode DMPlexShiftCoordinates_Private(DM dm, PetscInt depthShift[], DM dmNew)
3559 {
3560   PetscSection   coordSection, newCoordSection;
3561   Vec            coordinates;
3562   PetscInt      *depthEnd;
3563   PetscInt       dim, depth = 0, d, vStart, vEnd, v;
3564   PetscErrorCode ierr;
3565 
3566   PetscFunctionBegin;
3567   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3568   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3569   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3570   for(d = 0; d <= depth; ++d) {
3571     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3572   }
3573   /* Step 8: Convert coordinates */
3574   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);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, DMPlexShiftPoint_Private(vStart, depth, depthEnd, depthShift), DMPlexShiftPoint_Private(vEnd, depth, depthEnd, depthShift));CHKERRQ(ierr);
3580   for(v = vStart; v < vEnd; ++v) {
3581     const PetscInt newv = DMPlexShiftPoint_Private(v, depth, depthEnd, depthShift);
3582     ierr = PetscSectionSetDof(newCoordSection, newv, dim);CHKERRQ(ierr);
3583     ierr = PetscSectionSetFieldDof(newCoordSection, newv, 0, dim);CHKERRQ(ierr);
3584   }
3585   ierr = PetscSectionSetUp(newCoordSection);CHKERRQ(ierr);
3586   ierr = DMPlexSetCoordinateSection(dmNew, newCoordSection);CHKERRQ(ierr);
3587   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
3588   ierr = DMSetCoordinatesLocal(dmNew, coordinates);CHKERRQ(ierr);
3589   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3590   PetscFunctionReturn(0);
3591 }
3592 
3593 #undef __FUNCT__
3594 #define __FUNCT__ "DMPlexShiftSF_Private"
3595 PetscErrorCode DMPlexShiftSF_Private(DM dm, PetscInt depthShift[], DM dmNew)
3596 {
3597   PetscInt          *depthEnd;
3598   PetscInt           depth = 0, d;
3599   PetscSF            sfPoint, sfPointNew;
3600   const PetscSFNode *remotePoints;
3601   PetscSFNode       *gremotePoints;
3602   const PetscInt    *localPoints;
3603   PetscInt          *glocalPoints, *newLocation, *newRemoteLocation;
3604   PetscInt           numRoots, numLeaves, l, pStart, pEnd, totShift = 0;
3605   PetscMPIInt        numProcs;
3606   PetscErrorCode     ierr;
3607 
3608   PetscFunctionBegin;
3609   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3610   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3611   for(d = 0; d <= depth; ++d) {
3612     totShift += depthShift[d];
3613     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3614   }
3615   /* Step 9: Convert pointSF */
3616   ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
3617   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3618   ierr = DMGetPointSF(dmNew, &sfPointNew);CHKERRQ(ierr);
3619   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
3620   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
3621   if (numRoots >= 0) {
3622     ierr = PetscMalloc2(numRoots,PetscInt,&newLocation,pEnd-pStart,PetscInt,&newRemoteLocation);CHKERRQ(ierr);
3623     for(l=0; l<numRoots; l++) newLocation[l] = DMPlexShiftPoint_Private(l, depth, depthEnd, depthShift);
3624     ierr = PetscSFBcastBegin(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3625     ierr = PetscSFBcastEnd(sfPoint, MPIU_INT, newLocation, newRemoteLocation);CHKERRQ(ierr);
3626     ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &glocalPoints);CHKERRQ(ierr);
3627     ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &gremotePoints);CHKERRQ(ierr);
3628     for(l = 0; l < numLeaves; ++l) {
3629       glocalPoints[l]        = DMPlexShiftPoint_Private(localPoints[l], depth, depthEnd, depthShift);
3630       gremotePoints[l].rank  = remotePoints[l].rank;
3631       gremotePoints[l].index = newRemoteLocation[localPoints[l]];
3632     }
3633     ierr = PetscFree2(newLocation,newRemoteLocation);CHKERRQ(ierr);
3634     ierr = PetscSFSetGraph(sfPointNew, numRoots + totShift, numLeaves, glocalPoints, PETSC_OWN_POINTER, gremotePoints, PETSC_OWN_POINTER);CHKERRQ(ierr);
3635   }
3636   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3637   PetscFunctionReturn(0);
3638 }
3639 
3640 #undef __FUNCT__
3641 #define __FUNCT__ "DMPlexShiftLabels_Private"
3642 PetscErrorCode DMPlexShiftLabels_Private(DM dm, PetscInt depthShift[], DM dmNew)
3643 {
3644   PetscSF        sfPoint;
3645   DMLabel        vtkLabel, ghostLabel;
3646   PetscInt      *depthEnd;
3647   const PetscSFNode *leafRemote;
3648   const PetscInt    *leafLocal;
3649   PetscInt       depth = 0, d, numLeaves, numLabels, l, cStart, cEnd, c, fStart, fEnd, f;
3650   PetscMPIInt    rank;
3651   PetscErrorCode ierr;
3652 
3653   PetscFunctionBegin;
3654   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3655   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthEnd);CHKERRQ(ierr);
3656   for(d = 0; d <= depth; ++d) {
3657     ierr = DMPlexGetDepthStratum(dm, d, PETSC_NULL, &depthEnd[d]);CHKERRQ(ierr);
3658   }
3659   /* Step 10: Convert labels */
3660   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
3661   for(l = 0; l < numLabels; ++l) {
3662     DMLabel         label, newlabel;
3663     const char     *lname;
3664     PetscBool       isDepth;
3665     IS              valueIS;
3666     const PetscInt *values;
3667     PetscInt        numValues, val;
3668 
3669     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
3670     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
3671     if (isDepth) continue;
3672     ierr = DMPlexCreateLabel(dmNew, lname);CHKERRQ(ierr);
3673     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
3674     ierr = DMPlexGetLabel(dmNew, lname, &newlabel);CHKERRQ(ierr);
3675     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3676     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
3677     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3678     for(val = 0; val < numValues; ++val) {
3679       IS              pointIS;
3680       const PetscInt *points;
3681       PetscInt        numPoints, p;
3682 
3683       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
3684       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
3685       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
3686       for(p = 0; p < numPoints; ++p) {
3687         const PetscInt newpoint = DMPlexShiftPoint_Private(points[p], depth, depthEnd, depthShift);
3688 
3689         ierr = DMLabelSetValue(newlabel, newpoint, values[val]);CHKERRQ(ierr);
3690       }
3691       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
3692       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
3693     }
3694     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3695     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3696   }
3697   ierr = PetscFree(depthEnd);CHKERRQ(ierr);
3698   /* Step 11: Make label for output (vtk) and to mark ghost points (ghost) */
3699   ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
3700   ierr = DMGetPointSF(dm, &sfPoint);CHKERRQ(ierr);
3701   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3702   ierr = PetscSFGetGraph(sfPoint, PETSC_NULL, &numLeaves, &leafLocal, &leafRemote);CHKERRQ(ierr);
3703   ierr = DMPlexCreateLabel(dmNew, "vtk");CHKERRQ(ierr);
3704   ierr = DMPlexCreateLabel(dmNew, "ghost");CHKERRQ(ierr);
3705   ierr = DMPlexGetLabel(dmNew, "vtk", &vtkLabel);CHKERRQ(ierr);
3706   ierr = DMPlexGetLabel(dmNew, "ghost", &ghostLabel);CHKERRQ(ierr);
3707   for(l = 0, c = cStart; l < numLeaves && c < cEnd; ++l, ++c) {
3708     for(; c < leafLocal[l] && c < cEnd; ++c) {
3709       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3710     }
3711     if (leafLocal[l] >= cEnd) break;
3712     if (leafRemote[l].rank == rank) {
3713       ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3714     } else {
3715       ierr = DMLabelSetValue(ghostLabel, c, 2);CHKERRQ(ierr);
3716     }
3717   }
3718   for(; c < cEnd; ++c) {
3719     ierr = DMLabelSetValue(vtkLabel, c, 1);CHKERRQ(ierr);
3720   }
3721   if (0) {
3722     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3723     ierr = DMLabelView(vtkLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3724     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3725   }
3726   ierr = DMPlexGetHeightStratum(dmNew, 1, &fStart, &fEnd);CHKERRQ(ierr);
3727   for(f = fStart; f < fEnd; ++f) {
3728     PetscInt numCells;
3729 
3730     ierr = DMPlexGetSupportSize(dmNew, f, &numCells);CHKERRQ(ierr);
3731     if (numCells < 2) {
3732       ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);
3733     } else {
3734       const PetscInt *cells = PETSC_NULL;
3735       PetscInt        vA, vB;
3736 
3737       ierr = DMPlexGetSupport(dmNew, f, &cells);CHKERRQ(ierr);
3738       ierr = DMLabelGetValue(vtkLabel, cells[0], &vA);CHKERRQ(ierr);
3739       ierr = DMLabelGetValue(vtkLabel, cells[1], &vB);CHKERRQ(ierr);
3740       if (!vA && !vB) {ierr = DMLabelSetValue(ghostLabel, f, 1);CHKERRQ(ierr);}
3741     }
3742   }
3743   if (0) {
3744     ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
3745     ierr = DMLabelView(ghostLabel, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3746     ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
3747   }
3748   PetscFunctionReturn(0);
3749 }
3750 
3751 #undef __FUNCT__
3752 #define __FUNCT__ "DMPlexConstructGhostCells_2D"
3753 /*@C
3754   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3755 
3756   Collective on dm
3757 
3758   Input Parameters:
3759 + dm - The original DM
3760 - labelName - The label specifying the boundary faces (this could be auto-generated)
3761 
3762   Output Parameters:
3763 + numGhostCells - The number of ghost cells added to the DM
3764 - dmGhosted - The new DM
3765 
3766   Level: developer
3767 
3768 .seealso: DMCreate()
3769 */
3770 PetscErrorCode DMPlexConstructGhostCells_2D(DM dm, const char labelName[], PetscInt *numGhostCells, DM gdm)
3771 {
3772   DMLabel         label;
3773   IS              valueIS;
3774   const PetscInt *values;
3775   PetscInt       *depthShift;
3776   PetscInt        depth = 0, numFS, fs, ghostCell, cEnd, c;
3777   PetscErrorCode  ierr;
3778 
3779   PetscFunctionBegin;
3780   /* Count ghost cells */
3781   ierr = DMPlexGetLabel(dm, labelName ? labelName : "Face Sets", &label);CHKERRQ(ierr);
3782   ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
3783   ierr = ISGetLocalSize(valueIS, &numFS);CHKERRQ(ierr);
3784   ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
3785   *numGhostCells = 0;
3786   for(fs = 0; fs < numFS; ++fs) {
3787     PetscInt numBdFaces;
3788 
3789     ierr = DMLabelGetStratumSize(label, values[fs], &numBdFaces);CHKERRQ(ierr);
3790     *numGhostCells += numBdFaces;
3791   }
3792   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
3793   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthShift);CHKERRQ(ierr);
3794   ierr = PetscMemzero(depthShift, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
3795   if (depth >= 0) {depthShift[depth] = *numGhostCells;}
3796   ierr = DMPlexShiftSizes_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3797   /* Step 3: Set cone/support sizes for new points */
3798   ierr = DMPlexGetHeightStratum(dm, 0, PETSC_NULL, &cEnd);CHKERRQ(ierr);
3799   for(c = cEnd; c < cEnd + *numGhostCells; ++c) {
3800     ierr = DMPlexSetConeSize(gdm, c, 1);CHKERRQ(ierr);
3801   }
3802   for(fs = 0; fs < numFS; ++fs) {
3803     IS              faceIS;
3804     const PetscInt *faces;
3805     PetscInt        numFaces, f;
3806 
3807     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3808     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3809     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3810     for(f = 0; f < numFaces; ++f) {
3811       PetscInt size;
3812 
3813       ierr = DMPlexGetSupportSize(dm, faces[f], &size);CHKERRQ(ierr);
3814       if (size != 1) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "DM has boundary face %d with %d support cells", faces[f], size);
3815       ierr = DMPlexSetSupportSize(gdm, faces[f] + *numGhostCells, 2);CHKERRQ(ierr);
3816     }
3817     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3818     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3819   }
3820   /* Step 4: Setup ghosted DM */
3821   ierr = DMSetUp(gdm);CHKERRQ(ierr);
3822   ierr = DMPlexShiftPoints_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3823   /* Step 6: Set cones and supports for new points */
3824   ghostCell = cEnd;
3825   for(fs = 0; fs < numFS; ++fs) {
3826     IS              faceIS;
3827     const PetscInt *faces;
3828     PetscInt        numFaces, f;
3829 
3830     ierr = DMLabelGetStratumIS(label, values[fs], &faceIS);CHKERRQ(ierr);
3831     ierr = ISGetLocalSize(faceIS, &numFaces);CHKERRQ(ierr);
3832     ierr = ISGetIndices(faceIS, &faces);CHKERRQ(ierr);
3833     for(f = 0; f < numFaces; ++f, ++ghostCell) {
3834       PetscInt newFace = faces[f] + *numGhostCells;
3835 
3836       ierr = DMPlexSetCone(gdm, ghostCell, &newFace);CHKERRQ(ierr);
3837       ierr = DMPlexInsertSupport(gdm, newFace, 1, ghostCell);CHKERRQ(ierr);
3838     }
3839     ierr = ISRestoreIndices(faceIS, &faces);CHKERRQ(ierr);
3840     ierr = ISDestroy(&faceIS);CHKERRQ(ierr);
3841   }
3842   ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
3843   ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
3844   /* Step 7: Stratify */
3845   ierr = DMPlexStratify(gdm);CHKERRQ(ierr);
3846   ierr = DMPlexShiftCoordinates_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3847   ierr = DMPlexShiftSF_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3848   ierr = DMPlexShiftLabels_Private(dm, depthShift, gdm);CHKERRQ(ierr);
3849   ierr = PetscFree(depthShift);CHKERRQ(ierr);
3850   PetscFunctionReturn(0);
3851 }
3852 
3853 #undef __FUNCT__
3854 #define __FUNCT__ "DMPlexConstructGhostCells"
3855 /*@C
3856   DMPlexConstructGhostCells - Construct ghost cells which connect to every boundary face
3857 
3858   Collective on dm
3859 
3860   Input Parameters:
3861 + dm - The original DM
3862 - labelName - The label specifying the boundary faces (this could be auto-generated)
3863 
3864   Output Parameters:
3865 + numGhostCells - The number of ghost cells added to the DM
3866 - dmGhosted - The new DM
3867 
3868   Level: developer
3869 
3870 .seealso: DMCreate()
3871 */
3872 PetscErrorCode DMPlexConstructGhostCells(DM dm, const char labelName[], PetscInt *numGhostCells, DM *dmGhosted)
3873 {
3874   DM             gdm;
3875   PetscInt       dim;
3876   PetscErrorCode ierr;
3877 
3878   PetscFunctionBegin;
3879   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3880   PetscValidPointer(numGhostCells, 3);
3881   PetscValidPointer(dmGhosted, 4);
3882   ierr = DMCreate(((PetscObject) dm)->comm, &gdm);CHKERRQ(ierr);
3883   ierr = DMSetType(gdm, DMPLEX);CHKERRQ(ierr);
3884   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3885   ierr = DMPlexSetDimension(gdm, dim);CHKERRQ(ierr);
3886   switch(dim) {
3887   case 2:
3888     ierr = DMPlexConstructGhostCells_2D(dm, labelName, numGhostCells, gdm);CHKERRQ(ierr);
3889     break;
3890   default:
3891     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Cannot construct ghost cells for dimension %d", dim);
3892   }
3893   ierr = DMSetFromOptions(gdm);CHKERRQ(ierr);
3894   *dmGhosted = gdm;
3895   PetscFunctionReturn(0);
3896 }
3897 
3898 #undef __FUNCT__
3899 #define __FUNCT__ "DMPlexInterpolate_2D"
3900 PetscErrorCode DMPlexInterpolate_2D(DM dm, DM *dmInt)
3901 {
3902   DM             idm;
3903   DM_Plex    *mesh;
3904   PetscHashIJ    edgeTable;
3905   PetscInt      *off;
3906   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
3907   PetscInt       numEdges, firstEdge, edge, e;
3908   PetscErrorCode ierr;
3909 
3910   PetscFunctionBegin;
3911   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
3912   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
3913   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
3914   numCells    = cEnd - cStart;
3915   numVertices = vEnd - vStart;
3916   firstEdge   = numCells + numVertices;
3917   numEdges    = 0 ;
3918   /* Count edges using algorithm from CreateNeighborCSR */
3919   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
3920   if (off) {
3921     PetscInt numCorners = 0;
3922 
3923     numEdges = off[numCells]/2;
3924 #if 0
3925     /* Account for boundary edges: \sum_c 3 - neighbors = 3*numCells - totalNeighbors */
3926     numEdges += 3*numCells - off[numCells];
3927 #else
3928     /* Account for boundary edges: \sum_c #faces - #neighbors = \sum_c #cellVertices - #neighbors = totalCorners - totalNeighbors */
3929     for(c = cStart; c < cEnd; ++c) {
3930       PetscInt coneSize;
3931 
3932       ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
3933       numCorners += coneSize;
3934     }
3935     numEdges += numCorners - off[numCells];
3936 #endif
3937   }
3938 #if 0
3939   /* Check Euler characteristic V - E + F = 1 */
3940   if (numVertices && (numVertices-numEdges+numCells != 1)) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Euler characteristic of mesh is %d  != 1", numVertices-numEdges+numCells);
3941 #endif
3942   /* Create interpolated mesh */
3943   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
3944   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
3945   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
3946   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numEdges);CHKERRQ(ierr);
3947   for (c = 0; c < numCells; ++c) {
3948     PetscInt numCorners;
3949 
3950     ierr = DMPlexGetConeSize(dm, c, &numCorners);CHKERRQ(ierr);
3951     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
3952   }
3953   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
3954     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
3955   }
3956   ierr = DMSetUp(idm);CHKERRQ(ierr);
3957   /* Get edge cones from subsets of cell vertices */
3958   ierr = PetscHashIJCreate(&edgeTable);CHKERRQ(ierr);
3959   ierr = PetscHashIJSetMultivalued(edgeTable, PETSC_FALSE);CHKERRQ(ierr);
3960 
3961   for (c = 0, edge = firstEdge; c < numCells; ++c) {
3962     const PetscInt *cellFaces;
3963     PetscInt        numCellFaces, faceSize, cf;
3964 
3965     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
3966     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
3967     for (cf = 0; cf < numCellFaces; ++cf) {
3968 #if 1
3969       PetscHashIJKey key = {PetscMin(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1]),
3970                             PetscMax(cellFaces[cf*faceSize+0], cellFaces[cf*faceSize+1])};
3971 
3972       ierr = PetscHashIJGet(edgeTable, key, &e);CHKERRQ(ierr);
3973       if (e < 0) {
3974         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3975         ierr = PetscHashIJAdd(edgeTable, key, edge);CHKERRQ(ierr);
3976         e    = edge++;
3977       }
3978 #else
3979       PetscBool found = PETSC_FALSE;
3980 
3981       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
3982       for (e = firstEdge; e < edge; ++e) {
3983         const PetscInt *cone;
3984 
3985         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
3986         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
3987             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
3988           found = PETSC_TRUE;
3989           break;
3990         }
3991       }
3992       if (!found) {
3993         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
3994         ++edge;
3995       }
3996 #endif
3997       ierr = DMPlexInsertCone(idm, c, cf, e);CHKERRQ(ierr);
3998     }
3999   }
4000   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4001   ierr = PetscHashIJDestroy(&edgeTable);CHKERRQ(ierr);
4002   ierr = PetscFree(off);CHKERRQ(ierr);
4003   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4004   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4005   mesh = (DM_Plex *) (idm)->data;
4006   /* Orient edges */
4007   for (c = 0; c < numCells; ++c) {
4008     const PetscInt *cone = PETSC_NULL, *cellFaces;
4009     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4010 
4011     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4012     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4013     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4014     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4015     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4016     for (cf = 0; cf < numCellFaces; ++cf) {
4017       const PetscInt *econe = PETSC_NULL;
4018       PetscInt        esize;
4019 
4020       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4021       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4022       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]);
4023       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4024         /* Correctly oriented */
4025         mesh->coneOrientations[coff+cf] = 0;
4026       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4027         /* Start at index 1, and reverse orientation */
4028         mesh->coneOrientations[coff+cf] = -(1+1);
4029       }
4030     }
4031   }
4032   *dmInt  = idm;
4033   PetscFunctionReturn(0);
4034 }
4035 
4036 #undef __FUNCT__
4037 #define __FUNCT__ "DMPlexInterpolate_3D"
4038 PetscErrorCode DMPlexInterpolate_3D(DM dm, DM *dmInt)
4039 {
4040   DM             idm, fdm;
4041   DM_Plex    *mesh;
4042   PetscInt      *off;
4043   const PetscInt numCorners = 4;
4044   PetscInt       dim, numCells, cStart, cEnd, c, numVertices, vStart, vEnd;
4045   PetscInt       numFaces, firstFace, face, f, numEdges, firstEdge, edge, e;
4046   PetscErrorCode ierr;
4047 
4048   PetscFunctionBegin;
4049   {
4050     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4051     ierr = DMView(dm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4052     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4053   }
4054   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
4055   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4056   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4057   numCells    = cEnd - cStart;
4058   numVertices = vEnd - vStart;
4059   firstFace   = numCells + numVertices;
4060   numFaces    = 0 ;
4061   /* Count faces using algorithm from CreateNeighborCSR */
4062   ierr = DMPlexCreateNeighborCSR(dm, PETSC_NULL, &off, PETSC_NULL);CHKERRQ(ierr);
4063   if (off) {
4064     numFaces = off[numCells]/2;
4065     /* Account for boundary faces: \sum_c 4 - neighbors = 4*numCells - totalNeighbors */
4066     numFaces += 4*numCells - off[numCells];
4067   }
4068   /* Use Euler characteristic to get edges V - E + F - C = 1 */
4069   firstEdge = firstFace + numFaces;
4070   numEdges  = numVertices + numFaces - numCells - 1;
4071   /* Create interpolated mesh */
4072   ierr = DMCreate(((PetscObject) dm)->comm, &idm);CHKERRQ(ierr);
4073   ierr = DMSetType(idm, DMPLEX);CHKERRQ(ierr);
4074   ierr = DMPlexSetDimension(idm, dim);CHKERRQ(ierr);
4075   ierr = DMPlexSetChart(idm, 0, numCells+numVertices+numFaces+numEdges);CHKERRQ(ierr);
4076   for (c = 0; c < numCells; ++c) {
4077     ierr = DMPlexSetConeSize(idm, c, numCorners);CHKERRQ(ierr);
4078   }
4079   for (f = firstFace; f < firstFace+numFaces; ++f) {
4080     ierr = DMPlexSetConeSize(idm, f, 3);CHKERRQ(ierr);
4081   }
4082   for (e = firstEdge; e < firstEdge+numEdges; ++e) {
4083     ierr = DMPlexSetConeSize(idm, e, 2);CHKERRQ(ierr);
4084   }
4085   ierr = DMSetUp(idm);CHKERRQ(ierr);
4086   /* Get face cones from subsets of cell vertices */
4087   ierr = DMCreate(((PetscObject) dm)->comm, &fdm);CHKERRQ(ierr);
4088   ierr = DMSetType(fdm, DMPLEX);CHKERRQ(ierr);
4089   ierr = DMPlexSetDimension(fdm, dim);CHKERRQ(ierr);
4090   ierr = DMPlexSetChart(fdm, numCells, firstFace+numFaces);CHKERRQ(ierr);
4091   for (f = firstFace; f < firstFace+numFaces; ++f) {
4092     ierr = DMPlexSetConeSize(fdm, f, 3);CHKERRQ(ierr);
4093   }
4094   ierr = DMSetUp(fdm);CHKERRQ(ierr);
4095   for (c = 0, face = firstFace; c < numCells; ++c) {
4096     const PetscInt *cellFaces;
4097     PetscInt        numCellFaces, faceSize, cf;
4098 
4099     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4100     if (faceSize != 3) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Tetrahedra cannot have face of size %D", faceSize);
4101     for (cf = 0; cf < numCellFaces; ++cf) {
4102       PetscBool found = PETSC_FALSE;
4103 
4104       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4105       for (f = firstFace; f < face; ++f) {
4106         const PetscInt *cone = PETSC_NULL;
4107 
4108         ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4109         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[2])) ||
4110             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4111             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4112             ((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[2]) && (cellFaces[cf*faceSize+2] == cone[1])) ||
4113             ((cellFaces[cf*faceSize+0] == cone[2]) && (cellFaces[cf*faceSize+1] == cone[1]) && (cellFaces[cf*faceSize+2] == cone[0])) ||
4114             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]) && (cellFaces[cf*faceSize+2] == cone[2]))) {
4115           found = PETSC_TRUE;
4116           break;
4117         }
4118       }
4119       if (!found) {
4120         ierr = DMPlexSetCone(idm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4121         /* Save the vertices for orientation calculation */
4122         ierr = DMPlexSetCone(fdm, face, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4123         ++face;
4124       }
4125       ierr = DMPlexInsertCone(idm, c, cf, f);CHKERRQ(ierr);
4126     }
4127   }
4128   if (face != firstFace+numFaces) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of faces %D should be %D", face-firstFace, numFaces);
4129   /* Get edge cones from subsets of face vertices */
4130   for (f = firstFace, edge = firstEdge; f < firstFace+numFaces; ++f) {
4131     const PetscInt *cellFaces;
4132     PetscInt        numCellFaces, faceSize, cf;
4133 
4134     ierr = DMPlexGetFaces(idm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4135     if (faceSize != 2) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Triangles cannot have face of size %D", faceSize);
4136     for (cf = 0; cf < numCellFaces; ++cf) {
4137       PetscBool found = PETSC_FALSE;
4138 
4139       /* TODO Need join of vertices to check for existence of edges, which needs support (could set edge support), so just brute force for now */
4140       for (e = firstEdge; e < edge; ++e) {
4141         const PetscInt *cone = PETSC_NULL;
4142 
4143         ierr = DMPlexGetCone(idm, e, &cone);CHKERRQ(ierr);
4144         if (((cellFaces[cf*faceSize+0] == cone[0]) && (cellFaces[cf*faceSize+1] == cone[1])) ||
4145             ((cellFaces[cf*faceSize+0] == cone[1]) && (cellFaces[cf*faceSize+1] == cone[0]))) {
4146           found = PETSC_TRUE;
4147           break;
4148         }
4149       }
4150       if (!found) {
4151         ierr = DMPlexSetCone(idm, edge, &cellFaces[cf*faceSize]);CHKERRQ(ierr);
4152         ++edge;
4153       }
4154       ierr = DMPlexInsertCone(idm, f, cf, e);CHKERRQ(ierr);
4155     }
4156   }
4157   if (edge != firstEdge+numEdges) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D should be %D", edge-firstEdge, numEdges);
4158   ierr = PetscFree(off);CHKERRQ(ierr);
4159   ierr = DMPlexSymmetrize(idm);CHKERRQ(ierr);
4160   ierr = DMPlexStratify(idm);CHKERRQ(ierr);
4161   mesh = (DM_Plex *) (idm)->data;
4162   /* Orient edges */
4163   for (f = firstFace; f < firstFace+numFaces; ++f) {
4164     const PetscInt *cone, *cellFaces;
4165     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4166 
4167     ierr = DMPlexGetConeSize(idm, f, &coneSize);CHKERRQ(ierr);
4168     ierr = DMPlexGetCone(idm, f, &cone);CHKERRQ(ierr);
4169     ierr = PetscSectionGetOffset(mesh->coneSection, f, &coff);CHKERRQ(ierr);
4170     ierr = DMPlexGetFaces(fdm, f, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4171     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for face %D should be %D", coneSize, f, numCellFaces);
4172     for (cf = 0; cf < numCellFaces; ++cf) {
4173       const PetscInt *econe;
4174       PetscInt        esize;
4175 
4176       ierr = DMPlexGetConeSize(idm, cone[cf], &esize);CHKERRQ(ierr);
4177       ierr = DMPlexGetCone(idm, cone[cf], &econe);CHKERRQ(ierr);
4178       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]);
4179       if ((cellFaces[cf*faceSize+0] == econe[0]) && (cellFaces[cf*faceSize+1] == econe[1])) {
4180         /* Correctly oriented */
4181         mesh->coneOrientations[coff+cf] = 0;
4182       } else if ((cellFaces[cf*faceSize+0] == econe[1]) && (cellFaces[cf*faceSize+1] == econe[0])) {
4183         /* Start at index 1, and reverse orientation */
4184         mesh->coneOrientations[coff+cf] = -(1+1);
4185       }
4186     }
4187   }
4188   ierr = DMDestroy(&fdm);CHKERRQ(ierr);
4189   /* Orient faces */
4190   for (c = 0; c < numCells; ++c) {
4191     const PetscInt *cone, *cellFaces;
4192     PetscInt        coneSize, coff, numCellFaces, faceSize, cf;
4193 
4194     ierr = DMPlexGetConeSize(idm, c, &coneSize);CHKERRQ(ierr);
4195     ierr = DMPlexGetCone(idm, c, &cone);CHKERRQ(ierr);
4196     ierr = PetscSectionGetOffset(mesh->coneSection, c, &coff);CHKERRQ(ierr);
4197     ierr = DMPlexGetFaces(dm, c, &numCellFaces, &faceSize, &cellFaces);CHKERRQ(ierr);
4198     if (coneSize != numCellFaces) SETERRQ3(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid number of edges %D for cell %D should be %D", coneSize, c, numCellFaces);
4199     for (cf = 0; cf < numCellFaces; ++cf) {
4200       PetscInt *origClosure = PETSC_NULL, *closure;
4201       PetscInt  closureSize, i;
4202 
4203       ierr = DMPlexGetTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4204       if (closureSize != 7) SETERRQ2(((PetscObject) idm)->comm, PETSC_ERR_PLIB, "Invalid closure size %D for face %D should be 7", closureSize, cone[cf]);
4205       for (i = 4; i < 7; ++i) {
4206         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);
4207       }
4208       closure = &origClosure[4*2];
4209       /* Remember that this is the orientation for edges, not vertices */
4210       if        ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4211         /* Correctly oriented */
4212         mesh->coneOrientations[coff+cf] = 0;
4213       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4214         /* Shifted by 1 */
4215         mesh->coneOrientations[coff+cf] = 1;
4216       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4217         /* Shifted by 2 */
4218         mesh->coneOrientations[coff+cf] = 2;
4219       } else if ((cellFaces[cf*faceSize+0] == closure[2*2]) && (cellFaces[cf*faceSize+1] == closure[1*2]) && (cellFaces[cf*faceSize+2] == closure[0*2])) {
4220         /* Start at edge 1, and reverse orientation */
4221         mesh->coneOrientations[coff+cf] = -(1+1);
4222       } else if ((cellFaces[cf*faceSize+0] == closure[1*2]) && (cellFaces[cf*faceSize+1] == closure[0*2]) && (cellFaces[cf*faceSize+2] == closure[2*2])) {
4223         /* Start at index 0, and reverse orientation */
4224         mesh->coneOrientations[coff+cf] = -(0+1);
4225       } else if ((cellFaces[cf*faceSize+0] == closure[0*2]) && (cellFaces[cf*faceSize+1] == closure[2*2]) && (cellFaces[cf*faceSize+2] == closure[1*2])) {
4226         /* Start at index 2, and reverse orientation */
4227         mesh->coneOrientations[coff+cf] = -(2+1);
4228       } 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);
4229       ierr = DMPlexRestoreTransitiveClosure(idm, cone[cf], PETSC_TRUE, &closureSize, &origClosure);CHKERRQ(ierr);
4230     }
4231   }
4232   {
4233     ierr = PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_INFO_DETAIL);CHKERRQ(ierr);
4234     ierr = DMView(idm, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4235     ierr = PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
4236   }
4237   *dmInt  = idm;
4238   PetscFunctionReturn(0);
4239 }
4240 
4241 #undef __FUNCT__
4242 #define __FUNCT__ "DMPlexBuildFromCellList_Private"
4243 /*
4244   This takes as input the common mesh generator output, a list of the vertices for each cell
4245 */
4246 PetscErrorCode DMPlexBuildFromCellList_Private(DM dm, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, const int cells[])
4247 {
4248   PetscInt      *cone, c, p;
4249   PetscErrorCode ierr;
4250 
4251   PetscFunctionBegin;
4252   ierr = DMPlexSetChart(dm, 0, numCells+numVertices);CHKERRQ(ierr);
4253   for (c = 0; c < numCells; ++c) {
4254     ierr = DMPlexSetConeSize(dm, c, numCorners);CHKERRQ(ierr);
4255   }
4256   ierr = DMSetUp(dm);CHKERRQ(ierr);
4257   ierr = DMGetWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4258   for (c = 0; c < numCells; ++c) {
4259     for (p = 0; p < numCorners; ++p) {
4260       cone[p] = cells[c*numCorners+p]+numCells;
4261     }
4262     ierr = DMPlexSetCone(dm, c, cone);CHKERRQ(ierr);
4263   }
4264   ierr = DMRestoreWorkArray(dm, numCorners, PETSC_INT, &cone);CHKERRQ(ierr);
4265   ierr = DMPlexSymmetrize(dm);CHKERRQ(ierr);
4266   ierr = DMPlexStratify(dm);CHKERRQ(ierr);
4267   PetscFunctionReturn(0);
4268 }
4269 
4270 #undef __FUNCT__
4271 #define __FUNCT__ "DMPlexBuildCoordinates_Private"
4272 /*
4273   This takes as input the coordinates for each vertex
4274 */
4275 PetscErrorCode DMPlexBuildCoordinates_Private(DM dm, PetscInt spaceDim, PetscInt numCells, PetscInt numVertices, const double vertexCoords[])
4276 {
4277   PetscSection   coordSection;
4278   Vec            coordinates;
4279   PetscScalar   *coords;
4280   PetscInt       coordSize, v, d;
4281   PetscErrorCode ierr;
4282 
4283   PetscFunctionBegin;
4284   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4285   ierr = PetscSectionSetNumFields(coordSection, 1);CHKERRQ(ierr);
4286   ierr = PetscSectionSetFieldComponents(coordSection, 0, spaceDim);CHKERRQ(ierr);
4287   ierr = PetscSectionSetChart(coordSection, numCells, numCells + numVertices);CHKERRQ(ierr);
4288   for (v = numCells; v < numCells+numVertices; ++v) {
4289     ierr = PetscSectionSetDof(coordSection, v, spaceDim);CHKERRQ(ierr);
4290     ierr = PetscSectionSetFieldDof(coordSection, v, 0, spaceDim);CHKERRQ(ierr);
4291   }
4292   ierr = PetscSectionSetUp(coordSection);CHKERRQ(ierr);
4293   ierr = PetscSectionGetStorageSize(coordSection, &coordSize);CHKERRQ(ierr);
4294   ierr = VecCreate(((PetscObject) dm)->comm, &coordinates);CHKERRQ(ierr);
4295   ierr = PetscObjectSetName((PetscObject) coordinates, "coordinates");CHKERRQ(ierr);
4296   ierr = VecSetSizes(coordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
4297   ierr = VecSetFromOptions(coordinates);CHKERRQ(ierr);
4298   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
4299   for (v = 0; v < numVertices; ++v) {
4300     for (d = 0; d < spaceDim; ++d) {
4301       coords[v*spaceDim+d] = vertexCoords[v*spaceDim+d];
4302     }
4303   }
4304   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
4305   ierr = DMSetCoordinatesLocal(dm, coordinates);CHKERRQ(ierr);
4306   ierr = VecDestroy(&coordinates);CHKERRQ(ierr);
4307   PetscFunctionReturn(0);
4308 }
4309 
4310 #undef __FUNCT__
4311 #define __FUNCT__ "DMPlexCreateFromCellList"
4312 /*
4313   This takes as input the common mesh generator output, a list of the vertices for each cell
4314 */
4315 PetscErrorCode DMPlexCreateFromCellList(MPI_Comm comm, PetscInt dim, PetscInt numCells, PetscInt numVertices, PetscInt numCorners, PetscBool interpolate, const int cells[], const double vertexCoords[], DM *dm)
4316 {
4317   PetscErrorCode ierr;
4318 
4319   PetscFunctionBegin;
4320   ierr = DMCreate(comm, dm);CHKERRQ(ierr);
4321   ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr);
4322   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
4323   ierr = DMPlexBuildFromCellList_Private(*dm, numCells, numVertices, numCorners, cells);CHKERRQ(ierr);
4324   if (interpolate) {
4325     DM idm;
4326 
4327     switch(dim) {
4328     case 2:
4329       ierr = DMPlexInterpolate_2D(*dm, &idm);CHKERRQ(ierr);break;
4330     case 3:
4331       ierr = DMPlexInterpolate_3D(*dm, &idm);CHKERRQ(ierr);break;
4332     default:
4333       SETERRQ1(comm, PETSC_ERR_ARG_OUTOFRANGE, "No mesh interpolation support for dimension %D", dim);
4334     }
4335     ierr = DMDestroy(dm);CHKERRQ(ierr);
4336     *dm  = idm;
4337   }
4338   ierr = DMPlexBuildCoordinates_Private(*dm, dim, numCells, numVertices, vertexCoords);CHKERRQ(ierr);
4339   PetscFunctionReturn(0);
4340 }
4341 
4342 #ifdef PETSC_HAVE_TRIANGLE
4343 #include <triangle.h>
4344 
4345 #undef __FUNCT__
4346 #define __FUNCT__ "InitInput_Triangle"
4347 PetscErrorCode InitInput_Triangle(struct triangulateio *inputCtx) {
4348   PetscFunctionBegin;
4349   inputCtx->numberofpoints = 0;
4350   inputCtx->numberofpointattributes = 0;
4351   inputCtx->pointlist = PETSC_NULL;
4352   inputCtx->pointattributelist = PETSC_NULL;
4353   inputCtx->pointmarkerlist = PETSC_NULL;
4354   inputCtx->numberofsegments = 0;
4355   inputCtx->segmentlist = PETSC_NULL;
4356   inputCtx->segmentmarkerlist = PETSC_NULL;
4357   inputCtx->numberoftriangleattributes = 0;
4358   inputCtx->trianglelist = PETSC_NULL;
4359   inputCtx->numberofholes = 0;
4360   inputCtx->holelist = PETSC_NULL;
4361   inputCtx->numberofregions = 0;
4362   inputCtx->regionlist = PETSC_NULL;
4363   PetscFunctionReturn(0);
4364 }
4365 
4366 #undef __FUNCT__
4367 #define __FUNCT__ "InitOutput_Triangle"
4368 PetscErrorCode InitOutput_Triangle(struct triangulateio *outputCtx) {
4369   PetscFunctionBegin;
4370   outputCtx->numberofpoints = 0;
4371   outputCtx->pointlist = PETSC_NULL;
4372   outputCtx->pointattributelist = PETSC_NULL;
4373   outputCtx->pointmarkerlist = PETSC_NULL;
4374   outputCtx->numberoftriangles = 0;
4375   outputCtx->trianglelist = PETSC_NULL;
4376   outputCtx->triangleattributelist = PETSC_NULL;
4377   outputCtx->neighborlist = PETSC_NULL;
4378   outputCtx->segmentlist = PETSC_NULL;
4379   outputCtx->segmentmarkerlist = PETSC_NULL;
4380   outputCtx->numberofedges = 0;
4381   outputCtx->edgelist = PETSC_NULL;
4382   outputCtx->edgemarkerlist = PETSC_NULL;
4383   PetscFunctionReturn(0);
4384 }
4385 
4386 #undef __FUNCT__
4387 #define __FUNCT__ "FiniOutput_Triangle"
4388 PetscErrorCode FiniOutput_Triangle(struct triangulateio *outputCtx) {
4389   PetscFunctionBegin;
4390   free(outputCtx->pointmarkerlist);
4391   free(outputCtx->edgelist);
4392   free(outputCtx->edgemarkerlist);
4393   free(outputCtx->trianglelist);
4394   free(outputCtx->neighborlist);
4395   PetscFunctionReturn(0);
4396 }
4397 
4398 #undef __FUNCT__
4399 #define __FUNCT__ "DMPlexGenerate_Triangle"
4400 PetscErrorCode DMPlexGenerate_Triangle(DM boundary, PetscBool interpolate, DM *dm)
4401 {
4402   MPI_Comm             comm = ((PetscObject) boundary)->comm;
4403   PetscInt             dim              = 2;
4404   const PetscBool      createConvexHull = PETSC_FALSE;
4405   const PetscBool      constrained      = PETSC_FALSE;
4406   struct triangulateio in;
4407   struct triangulateio out;
4408   PetscInt             vStart, vEnd, v, eStart, eEnd, e;
4409   PetscMPIInt          rank;
4410   PetscErrorCode       ierr;
4411 
4412   PetscFunctionBegin;
4413   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4414   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4415   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4416   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4417   in.numberofpoints = vEnd - vStart;
4418   if (in.numberofpoints > 0) {
4419     PetscSection coordSection;
4420     Vec          coordinates;
4421     PetscScalar *array;
4422 
4423     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4424     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4425     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4426     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4427     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4428     for (v = vStart; v < vEnd; ++v) {
4429       const PetscInt idx = v - vStart;
4430       PetscInt       off, d;
4431 
4432       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4433       for (d = 0; d < dim; ++d) {
4434         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4435       }
4436       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4437     }
4438     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4439   }
4440   ierr  = DMPlexGetHeightStratum(boundary, 0, &eStart, &eEnd);CHKERRQ(ierr);
4441   in.numberofsegments = eEnd - eStart;
4442   if (in.numberofsegments > 0) {
4443     ierr = PetscMalloc(in.numberofsegments*2 * sizeof(int), &in.segmentlist);CHKERRQ(ierr);
4444     ierr = PetscMalloc(in.numberofsegments   * sizeof(int), &in.segmentmarkerlist);CHKERRQ(ierr);
4445     for (e = eStart; e < eEnd; ++e) {
4446       const PetscInt  idx = e - eStart;
4447       const PetscInt *cone;
4448 
4449       ierr = DMPlexGetCone(boundary, e, &cone);CHKERRQ(ierr);
4450       in.segmentlist[idx*2+0] = cone[0] - vStart;
4451       in.segmentlist[idx*2+1] = cone[1] - vStart;
4452       ierr = DMPlexGetLabelValue(boundary, "marker", e, &in.segmentmarkerlist[idx]);CHKERRQ(ierr);
4453     }
4454   }
4455 #if 0 /* Do not currently support holes */
4456   PetscReal *holeCoords;
4457   PetscInt   h, d;
4458 
4459   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4460   if (in.numberofholes > 0) {
4461     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4462     for (h = 0; h < in.numberofholes; ++h) {
4463       for (d = 0; d < dim; ++d) {
4464         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4465       }
4466     }
4467   }
4468 #endif
4469   if (!rank) {
4470     char args[32];
4471 
4472     /* Take away 'Q' for verbose output */
4473     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4474     if (createConvexHull) {
4475       ierr = PetscStrcat(args, "c");CHKERRQ(ierr);
4476     }
4477     if (constrained) {
4478       ierr = PetscStrcpy(args, "zepDQ");CHKERRQ(ierr);
4479     }
4480     triangulate(args, &in, &out, PETSC_NULL);
4481   }
4482   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4483   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4484   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4485   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4486   ierr = PetscFree(in.holelist);CHKERRQ(ierr);
4487 
4488   {
4489     const PetscInt numCorners  = 3;
4490     const PetscInt numCells    = out.numberoftriangles;
4491     const PetscInt numVertices = out.numberofpoints;
4492     const int     *cells       = out.trianglelist;
4493     const double  *meshCoords  = out.pointlist;
4494 
4495     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4496     /* Set labels */
4497     for (v = 0; v < numVertices; ++v) {
4498       if (out.pointmarkerlist[v]) {
4499         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4500       }
4501     }
4502     if (interpolate) {
4503       for (e = 0; e < out.numberofedges; e++) {
4504         if (out.edgemarkerlist[e]) {
4505           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4506           const PetscInt *edges;
4507           PetscInt        numEdges;
4508 
4509           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4510           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4511           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4512           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4513         }
4514       }
4515     }
4516     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4517   }
4518 #if 0 /* Do not currently support holes */
4519   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4520 #endif
4521   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4522   PetscFunctionReturn(0);
4523 }
4524 
4525 #undef __FUNCT__
4526 #define __FUNCT__ "DMPlexRefine_Triangle"
4527 PetscErrorCode DMPlexRefine_Triangle(DM dm, double *maxVolumes, DM *dmRefined)
4528 {
4529   MPI_Comm             comm = ((PetscObject) dm)->comm;
4530   PetscInt             dim  = 2;
4531   struct triangulateio in;
4532   struct triangulateio out;
4533   PetscInt             vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4534   PetscMPIInt          rank;
4535   PetscErrorCode       ierr;
4536 
4537   PetscFunctionBegin;
4538   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4539   ierr = InitInput_Triangle(&in);CHKERRQ(ierr);
4540   ierr = InitOutput_Triangle(&out);CHKERRQ(ierr);
4541   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4542   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4543   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4544   in.numberofpoints = vEnd - vStart;
4545   if (in.numberofpoints > 0) {
4546     PetscSection coordSection;
4547     Vec          coordinates;
4548     PetscScalar *array;
4549 
4550     ierr = PetscMalloc(in.numberofpoints*dim * sizeof(double), &in.pointlist);CHKERRQ(ierr);
4551     ierr = PetscMalloc(in.numberofpoints * sizeof(int), &in.pointmarkerlist);CHKERRQ(ierr);
4552     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4553     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4554     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4555     for (v = vStart; v < vEnd; ++v) {
4556       const PetscInt idx = v - vStart;
4557       PetscInt       off, d;
4558 
4559       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4560       for (d = 0; d < dim; ++d) {
4561         in.pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4562       }
4563       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4564     }
4565     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4566   }
4567   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4568   in.numberofcorners   = 3;
4569   in.numberoftriangles = cEnd - cStart;
4570   in.trianglearealist  = (double *) maxVolumes;
4571   if (in.numberoftriangles > 0) {
4572     ierr = PetscMalloc(in.numberoftriangles*in.numberofcorners * sizeof(int), &in.trianglelist);CHKERRQ(ierr);
4573     for (c = cStart; c < cEnd; ++c) {
4574       const PetscInt idx     = c - cStart;
4575       PetscInt      *closure = PETSC_NULL;
4576       PetscInt       closureSize;
4577 
4578       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4579       if ((closureSize != 4) && (closureSize != 7)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a triangle, %D vertices in closure", closureSize);
4580       for (v = 0; v < 3; ++v) {
4581         in.trianglelist[idx*in.numberofcorners + v] = closure[(v+closureSize-3)*2] - vStart;
4582       }
4583       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4584     }
4585   }
4586   /* TODO: Segment markers are missing on input */
4587 #if 0 /* Do not currently support holes */
4588   PetscReal *holeCoords;
4589   PetscInt   h, d;
4590 
4591   ierr = DMPlexGetHoles(boundary, &in.numberofholes, &holeCords);CHKERRQ(ierr);
4592   if (in.numberofholes > 0) {
4593     ierr = PetscMalloc(in.numberofholes*dim * sizeof(double), &in.holelist);CHKERRQ(ierr);
4594     for (h = 0; h < in.numberofholes; ++h) {
4595       for (d = 0; d < dim; ++d) {
4596         in.holelist[h*dim+d] = holeCoords[h*dim+d];
4597       }
4598     }
4599   }
4600 #endif
4601   if (!rank) {
4602     char args[32];
4603 
4604     /* Take away 'Q' for verbose output */
4605     ierr = PetscStrcpy(args, "pqezQra");CHKERRQ(ierr);
4606     triangulate(args, &in, &out, PETSC_NULL);
4607   }
4608   ierr = PetscFree(in.pointlist);CHKERRQ(ierr);
4609   ierr = PetscFree(in.pointmarkerlist);CHKERRQ(ierr);
4610   ierr = PetscFree(in.segmentlist);CHKERRQ(ierr);
4611   ierr = PetscFree(in.segmentmarkerlist);CHKERRQ(ierr);
4612   ierr = PetscFree(in.trianglelist);CHKERRQ(ierr);
4613 
4614   {
4615     const PetscInt numCorners  = 3;
4616     const PetscInt numCells    = out.numberoftriangles;
4617     const PetscInt numVertices = out.numberofpoints;
4618     const int     *cells       = out.trianglelist;
4619     const double  *meshCoords  = out.pointlist;
4620     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4621 
4622     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4623     /* Set labels */
4624     for (v = 0; v < numVertices; ++v) {
4625       if (out.pointmarkerlist[v]) {
4626         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4627       }
4628     }
4629     if (interpolate) {
4630       PetscInt e;
4631 
4632       for (e = 0; e < out.numberofedges; e++) {
4633         if (out.edgemarkerlist[e]) {
4634           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4635           const PetscInt *edges;
4636           PetscInt        numEdges;
4637 
4638           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4639           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4640           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4641           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4642         }
4643       }
4644     }
4645     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4646   }
4647 #if 0 /* Do not currently support holes */
4648   ierr = DMPlexCopyHoles(*dm, boundary);CHKERRQ(ierr);
4649 #endif
4650   ierr = FiniOutput_Triangle(&out);CHKERRQ(ierr);
4651   PetscFunctionReturn(0);
4652 }
4653 #endif
4654 
4655 #ifdef PETSC_HAVE_TETGEN
4656 #include <tetgen.h>
4657 #undef __FUNCT__
4658 #define __FUNCT__ "DMPlexGenerate_Tetgen"
4659 PetscErrorCode DMPlexGenerate_Tetgen(DM boundary, PetscBool interpolate, DM *dm)
4660 {
4661   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4662   const PetscInt dim  = 3;
4663   ::tetgenio     in;
4664   ::tetgenio     out;
4665   PetscInt       vStart, vEnd, v, fStart, fEnd, f;
4666   PetscMPIInt    rank;
4667   PetscErrorCode ierr;
4668 
4669   PetscFunctionBegin;
4670   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4671   ierr  = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4672   in.numberofpoints = vEnd - vStart;
4673   if (in.numberofpoints > 0) {
4674     PetscSection coordSection;
4675     Vec          coordinates;
4676     PetscScalar *array;
4677 
4678     in.pointlist       = new double[in.numberofpoints*dim];
4679     in.pointmarkerlist = new int[in.numberofpoints];
4680     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4681     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4682     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4683     for (v = vStart; v < vEnd; ++v) {
4684       const PetscInt idx = v - vStart;
4685       PetscInt       off, d;
4686 
4687       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4688       for (d = 0; d < dim; ++d) {
4689         in.pointlist[idx*dim + d] = array[off+d];
4690       }
4691       ierr = DMPlexGetLabelValue(boundary, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4692     }
4693     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4694   }
4695   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4696   in.numberoffacets = fEnd - fStart;
4697   if (in.numberoffacets > 0) {
4698     in.facetlist       = new tetgenio::facet[in.numberoffacets];
4699     in.facetmarkerlist = new int[in.numberoffacets];
4700     for (f = fStart; f < fEnd; ++f) {
4701       const PetscInt idx    = f - fStart;
4702       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v;
4703 
4704       in.facetlist[idx].numberofpolygons = 1;
4705       in.facetlist[idx].polygonlist      = new tetgenio::polygon[in.facetlist[idx].numberofpolygons];
4706       in.facetlist[idx].numberofholes    = 0;
4707       in.facetlist[idx].holelist         = NULL;
4708 
4709       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4710       for (p = 0; p < numPoints*2; p += 2) {
4711         const PetscInt point = points[p];
4712         if ((point >= vStart) && (point < vEnd)) {
4713           points[numVertices++] = point;
4714         }
4715       }
4716 
4717       tetgenio::polygon *poly = in.facetlist[idx].polygonlist;
4718       poly->numberofvertices = numVertices;
4719       poly->vertexlist       = new int[poly->numberofvertices];
4720       for (v = 0; v < numVertices; ++v) {
4721         const PetscInt vIdx = points[v] - vStart;
4722         poly->vertexlist[v] = vIdx;
4723       }
4724       ierr = DMPlexGetLabelValue(boundary, "marker", f, &in.facetmarkerlist[idx]);CHKERRQ(ierr);
4725       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4726     }
4727   }
4728   if (!rank) {
4729     char args[32];
4730 
4731     /* Take away 'Q' for verbose output */
4732     ierr = PetscStrcpy(args, "pqezQ");CHKERRQ(ierr);
4733     ::tetrahedralize(args, &in, &out);
4734   }
4735   {
4736     const PetscInt numCorners  = 4;
4737     const PetscInt numCells    = out.numberoftetrahedra;
4738     const PetscInt numVertices = out.numberofpoints;
4739     const int     *cells       = out.tetrahedronlist;
4740     const double  *meshCoords  = out.pointlist;
4741 
4742     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
4743     /* Set labels */
4744     for (v = 0; v < numVertices; ++v) {
4745       if (out.pointmarkerlist[v]) {
4746         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4747       }
4748     }
4749     if (interpolate) {
4750       PetscInt e;
4751 
4752       for (e = 0; e < out.numberofedges; e++) {
4753         if (out.edgemarkerlist[e]) {
4754           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4755           const PetscInt *edges;
4756           PetscInt        numEdges;
4757 
4758           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4759           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4760           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4761           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4762         }
4763       }
4764       for (f = 0; f < out.numberoftrifaces; f++) {
4765         if (out.trifacemarkerlist[f]) {
4766           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4767           const PetscInt *faces;
4768           PetscInt        numFaces;
4769 
4770           ierr = DMPlexGetJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4771           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4772           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4773           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4774         }
4775       }
4776     }
4777     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
4778   }
4779   PetscFunctionReturn(0);
4780 }
4781 
4782 #undef __FUNCT__
4783 #define __FUNCT__ "DMPlexRefine_Tetgen"
4784 PetscErrorCode DMPlexRefine_Tetgen(DM dm, double *maxVolumes, DM *dmRefined)
4785 {
4786   MPI_Comm       comm = ((PetscObject) dm)->comm;
4787   const PetscInt dim  = 3;
4788   ::tetgenio     in;
4789   ::tetgenio     out;
4790   PetscInt       vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
4791   PetscMPIInt    rank;
4792   PetscErrorCode ierr;
4793 
4794   PetscFunctionBegin;
4795   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4796   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
4797   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
4798   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
4799   in.numberofpoints = vEnd - vStart;
4800   if (in.numberofpoints > 0) {
4801     PetscSection coordSection;
4802     Vec          coordinates;
4803     PetscScalar *array;
4804 
4805     in.pointlist       = new double[in.numberofpoints*dim];
4806     in.pointmarkerlist = new int[in.numberofpoints];
4807     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
4808     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
4809     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4810     for (v = vStart; v < vEnd; ++v) {
4811       const PetscInt idx = v - vStart;
4812       PetscInt       off, d;
4813 
4814       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4815       for (d = 0; d < dim; ++d) {
4816         in.pointlist[idx*dim + d] = array[off+d];
4817       }
4818       ierr = DMPlexGetLabelValue(dm, "marker", v, &in.pointmarkerlist[idx]);CHKERRQ(ierr);
4819     }
4820     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4821   }
4822   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
4823   in.numberofcorners       = 4;
4824   in.numberoftetrahedra    = cEnd - cStart;
4825   in.tetrahedronvolumelist = (double *) maxVolumes;
4826   if (in.numberoftetrahedra > 0) {
4827     in.tetrahedronlist = new int[in.numberoftetrahedra*in.numberofcorners];
4828     for (c = cStart; c < cEnd; ++c) {
4829       const PetscInt idx     = c - cStart;
4830       PetscInt      *closure = PETSC_NULL;
4831       PetscInt       closureSize;
4832 
4833       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4834       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
4835       for (v = 0; v < 4; ++v) {
4836         in.tetrahedronlist[idx*in.numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
4837       }
4838       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
4839     }
4840   }
4841   // TODO: Put in boundary faces with markers
4842   if (!rank) {
4843     char args[32];
4844 
4845     /* Take away 'Q' for verbose output */
4846     //ierr = PetscStrcpy(args, "qezQra");CHKERRQ(ierr);
4847     ierr = PetscStrcpy(args, "qezraVVVV");CHKERRQ(ierr);
4848     ::tetrahedralize(args, &in, &out);
4849   }
4850   in.tetrahedronvolumelist = NULL;
4851 
4852   {
4853     const PetscInt numCorners  = 4;
4854     const PetscInt numCells    = out.numberoftetrahedra;
4855     const PetscInt numVertices = out.numberofpoints;
4856     const int     *cells       = out.tetrahedronlist;
4857     const double  *meshCoords  = out.pointlist;
4858     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
4859 
4860     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
4861     /* Set labels */
4862     for (v = 0; v < numVertices; ++v) {
4863       if (out.pointmarkerlist[v]) {
4864         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out.pointmarkerlist[v]);CHKERRQ(ierr);
4865       }
4866     }
4867     if (interpolate) {
4868       PetscInt e, f;
4869 
4870       for (e = 0; e < out.numberofedges; e++) {
4871         if (out.edgemarkerlist[e]) {
4872           const PetscInt vertices[2] = {out.edgelist[e*2+0]+numCells, out.edgelist[e*2+1]+numCells};
4873           const PetscInt *edges;
4874           PetscInt        numEdges;
4875 
4876           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4877           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
4878           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out.edgemarkerlist[e]);CHKERRQ(ierr);
4879           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
4880         }
4881       }
4882       for (f = 0; f < out.numberoftrifaces; f++) {
4883         if (out.trifacemarkerlist[f]) {
4884           const PetscInt vertices[3] = {out.trifacelist[f*3+0]+numCells, out.trifacelist[f*3+1]+numCells, out.trifacelist[f*3+2]+numCells};
4885           const PetscInt *faces;
4886           PetscInt        numFaces;
4887 
4888           ierr = DMPlexGetJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4889           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
4890           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out.trifacemarkerlist[f]);CHKERRQ(ierr);
4891           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
4892         }
4893       }
4894     }
4895     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
4896   }
4897   PetscFunctionReturn(0);
4898 }
4899 #endif
4900 
4901 #ifdef PETSC_HAVE_CTETGEN
4902 #include "ctetgen.h"
4903 
4904 #undef __FUNCT__
4905 #define __FUNCT__ "DMPlexGenerate_CTetgen"
4906 PetscErrorCode DMPlexGenerate_CTetgen(DM boundary, PetscBool interpolate, DM *dm)
4907 {
4908   MPI_Comm       comm = ((PetscObject) boundary)->comm;
4909   const PetscInt dim  = 3;
4910   PLC           *in, *out;
4911   PetscInt       verbose = 0, vStart, vEnd, v, fStart, fEnd, f;
4912   PetscMPIInt    rank;
4913   PetscErrorCode ierr;
4914 
4915   PetscFunctionBegin;
4916   ierr = PetscOptionsGetInt(((PetscObject) boundary)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
4917   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
4918   ierr = DMPlexGetDepthStratum(boundary, 0, &vStart, &vEnd);CHKERRQ(ierr);
4919   ierr = PLCCreate(&in);CHKERRQ(ierr);
4920   ierr = PLCCreate(&out);CHKERRQ(ierr);
4921   in->numberofpoints = vEnd - vStart;
4922   if (in->numberofpoints > 0) {
4923     PetscSection coordSection;
4924     Vec          coordinates;
4925     PetscScalar *array;
4926 
4927     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
4928     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
4929     ierr = DMGetCoordinatesLocal(boundary, &coordinates);CHKERRQ(ierr);
4930     ierr = DMPlexGetCoordinateSection(boundary, &coordSection);CHKERRQ(ierr);
4931     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
4932     for (v = vStart; v < vEnd; ++v) {
4933       const PetscInt idx = v - vStart;
4934       PetscInt       off, d, m;
4935 
4936       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
4937       for (d = 0; d < dim; ++d) {
4938         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
4939       }
4940       ierr = DMPlexGetLabelValue(boundary, "marker", v, &m);CHKERRQ(ierr);
4941       in->pointmarkerlist[idx] = (int) m;
4942     }
4943     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
4944   }
4945   ierr  = DMPlexGetHeightStratum(boundary, 0, &fStart, &fEnd);CHKERRQ(ierr);
4946   in->numberoffacets = fEnd - fStart;
4947   if (in->numberoffacets > 0) {
4948     ierr = PetscMalloc(in->numberoffacets * sizeof(facet), &in->facetlist);CHKERRQ(ierr);
4949     ierr = PetscMalloc(in->numberoffacets * sizeof(int),   &in->facetmarkerlist);CHKERRQ(ierr);
4950     for (f = fStart; f < fEnd; ++f) {
4951       const PetscInt idx    = f - fStart;
4952       PetscInt      *points = PETSC_NULL, numPoints, p, numVertices = 0, v, m;
4953       polygon       *poly;
4954 
4955       in->facetlist[idx].numberofpolygons = 1;
4956       ierr = PetscMalloc(in->facetlist[idx].numberofpolygons * sizeof(polygon), &in->facetlist[idx].polygonlist);CHKERRQ(ierr);
4957       in->facetlist[idx].numberofholes    = 0;
4958       in->facetlist[idx].holelist         = PETSC_NULL;
4959 
4960       ierr = DMPlexGetTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4961       for (p = 0; p < numPoints*2; p += 2) {
4962         const PetscInt point = points[p];
4963         if ((point >= vStart) && (point < vEnd)) {
4964           points[numVertices++] = point;
4965         }
4966       }
4967 
4968       poly = in->facetlist[idx].polygonlist;
4969       poly->numberofvertices = numVertices;
4970       ierr = PetscMalloc(poly->numberofvertices * sizeof(int), &poly->vertexlist);CHKERRQ(ierr);
4971       for (v = 0; v < numVertices; ++v) {
4972         const PetscInt vIdx = points[v] - vStart;
4973         poly->vertexlist[v] = vIdx;
4974       }
4975       ierr = DMPlexGetLabelValue(boundary, "marker", f, &m);CHKERRQ(ierr);
4976       in->facetmarkerlist[idx] = (int) m;
4977       ierr = DMPlexRestoreTransitiveClosure(boundary, f, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
4978     }
4979   }
4980   if (!rank) {
4981     TetGenOpts t;
4982 
4983     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
4984     t.in        = boundary; /* Should go away */
4985     t.plc       = 1;
4986     t.quality   = 1;
4987     t.edgesout  = 1;
4988     t.zeroindex = 1;
4989     t.quiet     = 1;
4990     t.verbose   = verbose;
4991     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
4992     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
4993   }
4994   {
4995     const PetscInt numCorners  = 4;
4996     const PetscInt numCells    = out->numberoftetrahedra;
4997     const PetscInt numVertices = out->numberofpoints;
4998     const int     *cells       = out->tetrahedronlist;
4999     const double  *meshCoords  = out->pointlist;
5000 
5001     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dm);CHKERRQ(ierr);
5002     /* Set labels */
5003     for (v = 0; v < numVertices; ++v) {
5004       if (out->pointmarkerlist[v]) {
5005         ierr = DMPlexSetLabelValue(*dm, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5006       }
5007     }
5008     if (interpolate) {
5009       PetscInt e;
5010 
5011       for (e = 0; e < out->numberofedges; e++) {
5012         if (out->edgemarkerlist[e]) {
5013           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5014           const PetscInt *edges;
5015           PetscInt        numEdges;
5016 
5017           ierr = DMPlexGetJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5018           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5019           ierr = DMPlexSetLabelValue(*dm, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5020           ierr = DMPlexRestoreJoin(*dm, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5021         }
5022       }
5023       for (f = 0; f < out->numberoftrifaces; f++) {
5024         if (out->trifacemarkerlist[f]) {
5025           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5026           const PetscInt *faces;
5027           PetscInt        numFaces;
5028 
5029           ierr = DMPlexGetFullJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5030           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5031           ierr = DMPlexSetLabelValue(*dm, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5032           ierr = DMPlexRestoreJoin(*dm, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5033         }
5034       }
5035     }
5036     ierr = DMPlexSetRefinementUniform(*dm, PETSC_FALSE);CHKERRQ(ierr);
5037   }
5038 
5039   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5040   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5041   PetscFunctionReturn(0);
5042 }
5043 
5044 #undef __FUNCT__
5045 #define __FUNCT__ "DMPlexRefine_CTetgen"
5046 PetscErrorCode DMPlexRefine_CTetgen(DM dm, PetscReal *maxVolumes, DM *dmRefined)
5047 {
5048   MPI_Comm       comm = ((PetscObject) dm)->comm;
5049   const PetscInt dim  = 3;
5050   PLC           *in, *out;
5051   PetscInt       verbose = 0, vStart, vEnd, v, cStart, cEnd, c, depth, depthGlobal;
5052   PetscMPIInt    rank;
5053   PetscErrorCode ierr;
5054 
5055   PetscFunctionBegin;
5056   ierr = PetscOptionsGetInt(((PetscObject) dm)->prefix, "-ctetgen_verbose", &verbose, PETSC_NULL);CHKERRQ(ierr);
5057   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
5058   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5059   ierr = MPI_Allreduce(&depth, &depthGlobal, 1, MPIU_INT, MPI_MAX, comm);CHKERRQ(ierr);
5060   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5061   ierr = PLCCreate(&in);CHKERRQ(ierr);
5062   ierr = PLCCreate(&out);CHKERRQ(ierr);
5063   in->numberofpoints = vEnd - vStart;
5064   if (in->numberofpoints > 0) {
5065     PetscSection coordSection;
5066     Vec          coordinates;
5067     PetscScalar *array;
5068 
5069     ierr = PetscMalloc(in->numberofpoints*dim * sizeof(PetscReal), &in->pointlist);CHKERRQ(ierr);
5070     ierr = PetscMalloc(in->numberofpoints     * sizeof(int),       &in->pointmarkerlist);CHKERRQ(ierr);
5071     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5072     ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5073     ierr = VecGetArray(coordinates, &array);CHKERRQ(ierr);
5074     for (v = vStart; v < vEnd; ++v) {
5075       const PetscInt idx = v - vStart;
5076       PetscInt       off, d, m;
5077 
5078       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5079       for (d = 0; d < dim; ++d) {
5080         in->pointlist[idx*dim + d] = PetscRealPart(array[off+d]);
5081       }
5082       ierr = DMPlexGetLabelValue(dm, "marker", v, &m);CHKERRQ(ierr);
5083       in->pointmarkerlist[idx] = (int) m;
5084     }
5085     ierr = VecRestoreArray(coordinates, &array);CHKERRQ(ierr);
5086   }
5087   ierr  = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5088   in->numberofcorners       = 4;
5089   in->numberoftetrahedra    = cEnd - cStart;
5090   in->tetrahedronvolumelist = maxVolumes;
5091   if (in->numberoftetrahedra > 0) {
5092     ierr = PetscMalloc(in->numberoftetrahedra*in->numberofcorners * sizeof(int), &in->tetrahedronlist);CHKERRQ(ierr);
5093     for (c = cStart; c < cEnd; ++c) {
5094       const PetscInt idx     = c - cStart;
5095       PetscInt      *closure = PETSC_NULL;
5096       PetscInt       closureSize;
5097 
5098       ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5099       if ((closureSize != 5) && (closureSize != 15)) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Mesh has cell which is not a tetrahedron, %D vertices in closure", closureSize);
5100       for (v = 0; v < 4; ++v) {
5101         in->tetrahedronlist[idx*in->numberofcorners + v] = closure[(v+closureSize-4)*2] - vStart;
5102       }
5103       ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
5104     }
5105   }
5106   if (!rank) {
5107     TetGenOpts t;
5108 
5109     ierr = TetGenOptsInitialize(&t);CHKERRQ(ierr);
5110     t.in        = dm; /* Should go away */
5111     t.refine    = 1;
5112     t.varvolume = 1;
5113     t.quality   = 1;
5114     t.edgesout  = 1;
5115     t.zeroindex = 1;
5116     t.quiet     = 1;
5117     t.verbose   = verbose; /* Change this */
5118     ierr = TetGenCheckOpts(&t);CHKERRQ(ierr);
5119     ierr = TetGenTetrahedralize(&t, in, out);CHKERRQ(ierr);
5120   }
5121   {
5122     const PetscInt numCorners  = 4;
5123     const PetscInt numCells    = out->numberoftetrahedra;
5124     const PetscInt numVertices = out->numberofpoints;
5125     const int     *cells       = out->tetrahedronlist;
5126     const double  *meshCoords  = out->pointlist;
5127     PetscBool      interpolate = depthGlobal > 1 ? PETSC_TRUE : PETSC_FALSE;
5128 
5129     ierr = DMPlexCreateFromCellList(comm, dim, numCells, numVertices, numCorners, interpolate, cells, meshCoords, dmRefined);CHKERRQ(ierr);
5130     /* Set labels */
5131     for (v = 0; v < numVertices; ++v) {
5132       if (out->pointmarkerlist[v]) {
5133         ierr = DMPlexSetLabelValue(*dmRefined, "marker", v+numCells, out->pointmarkerlist[v]);CHKERRQ(ierr);
5134       }
5135     }
5136     if (interpolate) {
5137       PetscInt e, f;
5138 
5139       for (e = 0; e < out->numberofedges; e++) {
5140         if (out->edgemarkerlist[e]) {
5141           const PetscInt vertices[2] = {out->edgelist[e*2+0]+numCells, out->edgelist[e*2+1]+numCells};
5142           const PetscInt *edges;
5143           PetscInt        numEdges;
5144 
5145           ierr = DMPlexGetJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5146           if (numEdges != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Two vertices must cover only one edge, not %D", numEdges);
5147           ierr = DMPlexSetLabelValue(*dmRefined, "marker", edges[0], out->edgemarkerlist[e]);CHKERRQ(ierr);
5148           ierr = DMPlexRestoreJoin(*dmRefined, 2, vertices, &numEdges, &edges);CHKERRQ(ierr);
5149         }
5150       }
5151       for (f = 0; f < out->numberoftrifaces; f++) {
5152         if (out->trifacemarkerlist[f]) {
5153           const PetscInt vertices[3] = {out->trifacelist[f*3+0]+numCells, out->trifacelist[f*3+1]+numCells, out->trifacelist[f*3+2]+numCells};
5154           const PetscInt *faces;
5155           PetscInt        numFaces;
5156 
5157           ierr = DMPlexGetFullJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5158           if (numFaces != 1) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Three vertices must cover only one face, not %D", numFaces);
5159           ierr = DMPlexSetLabelValue(*dmRefined, "marker", faces[0], out->trifacemarkerlist[f]);CHKERRQ(ierr);
5160           ierr = DMPlexRestoreJoin(*dmRefined, 3, vertices, &numFaces, &faces);CHKERRQ(ierr);
5161         }
5162       }
5163     }
5164     ierr = DMPlexSetRefinementUniform(*dmRefined, PETSC_FALSE);CHKERRQ(ierr);
5165   }
5166   ierr = PLCDestroy(&in);CHKERRQ(ierr);
5167   ierr = PLCDestroy(&out);CHKERRQ(ierr);
5168   PetscFunctionReturn(0);
5169 }
5170 #endif
5171 
5172 #undef __FUNCT__
5173 #define __FUNCT__ "DMPlexGenerate"
5174 /*@C
5175   DMPlexGenerate - Generates a mesh.
5176 
5177   Not Collective
5178 
5179   Input Parameters:
5180 + boundary - The DMPlex boundary object
5181 . name - The mesh generation package name
5182 - interpolate - Flag to create intermediate mesh elements
5183 
5184   Output Parameter:
5185 . mesh - The DMPlex object
5186 
5187   Level: intermediate
5188 
5189 .keywords: mesh, elements
5190 .seealso: DMPlexCreate(), DMRefine()
5191 @*/
5192 PetscErrorCode DMPlexGenerate(DM boundary, const char name[], PetscBool interpolate, DM *mesh)
5193 {
5194   PetscInt       dim;
5195   char           genname[1024];
5196   PetscBool      isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
5197   PetscErrorCode ierr;
5198 
5199   PetscFunctionBegin;
5200   PetscValidHeaderSpecific(boundary, DM_CLASSID, 1);
5201   PetscValidLogicalCollectiveBool(boundary, interpolate, 2);
5202   ierr = DMPlexGetDimension(boundary, &dim);CHKERRQ(ierr);
5203   ierr = PetscOptionsGetString(((PetscObject) boundary)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
5204   if (flg) {name = genname;}
5205   if (name) {
5206     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
5207     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
5208     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
5209   }
5210   switch(dim) {
5211   case 1:
5212     if (!name || isTriangle) {
5213 #ifdef PETSC_HAVE_TRIANGLE
5214       ierr = DMPlexGenerate_Triangle(boundary, interpolate, mesh);CHKERRQ(ierr);
5215 #else
5216       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation needs external package support.\nPlease reconfigure with --download-triangle.");
5217 #endif
5218     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
5219     break;
5220   case 2:
5221     if (!name || isCTetgen) {
5222 #ifdef PETSC_HAVE_CTETGEN
5223       ierr = DMPlexGenerate_CTetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5224 #else
5225       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
5226 #endif
5227     } else if (isTetgen) {
5228 #ifdef PETSC_HAVE_TETGEN
5229       ierr = DMPlexGenerate_Tetgen(boundary, interpolate, mesh);CHKERRQ(ierr);
5230 #else
5231       SETERRQ(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
5232 #endif
5233     } else SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
5234     break;
5235   default:
5236     SETERRQ1(((PetscObject) boundary)->comm, PETSC_ERR_SUP, "Mesh generation for a dimension %d boundary is not supported.", dim);
5237   }
5238   PetscFunctionReturn(0);
5239 }
5240 
5241 typedef PetscInt CellRefiner;
5242 
5243 #undef __FUNCT__
5244 #define __FUNCT__ "GetDepthStart_Private"
5245 PETSC_STATIC_INLINE PetscErrorCode GetDepthStart_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cStart, PetscInt *fStart, PetscInt *eStart, PetscInt *vStart)
5246 {
5247   PetscFunctionBegin;
5248   if (cStart) *cStart = 0;
5249   if (vStart) *vStart = depthSize[depth];
5250   if (fStart) *fStart = depthSize[depth] + depthSize[0];
5251   if (eStart) *eStart = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5252   PetscFunctionReturn(0);
5253 }
5254 
5255 #undef __FUNCT__
5256 #define __FUNCT__ "GetDepthEnd_Private"
5257 PETSC_STATIC_INLINE PetscErrorCode GetDepthEnd_Private(PetscInt depth, PetscInt depthSize[], PetscInt *cEnd, PetscInt *fEnd, PetscInt *eEnd, PetscInt *vEnd)
5258 {
5259   PetscFunctionBegin;
5260   if (cEnd) *cEnd = depthSize[depth];
5261   if (vEnd) *vEnd = depthSize[depth] + depthSize[0];
5262   if (fEnd) *fEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1];
5263   if (eEnd) *eEnd = depthSize[depth] + depthSize[0] + depthSize[depth-1] + depthSize[1];
5264   PetscFunctionReturn(0);
5265 }
5266 
5267 #undef __FUNCT__
5268 #define __FUNCT__ "CellRefinerGetSizes"
5269 PetscErrorCode CellRefinerGetSizes(CellRefiner refiner, DM dm, PetscInt depthSize[])
5270 {
5271   PetscInt       cStart, cEnd, vStart, vEnd, fStart, fEnd, eStart, eEnd;
5272   PetscErrorCode ierr;
5273 
5274   PetscFunctionBegin;
5275   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5276   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5277   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5278   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5279   switch(refiner) {
5280   case 1:
5281     /* Simplicial 2D */
5282     depthSize[0] = vEnd - vStart + fEnd - fStart;         /* Add a vertex on every face */
5283     depthSize[1] = 2*(fEnd - fStart) + 3*(cEnd - cStart); /* Every face is split into 2 faces and 3 faces are added for each cell */
5284     depthSize[2] = 4*(cEnd - cStart);                     /* Every cell split into 4 cells */
5285     break;
5286   case 2:
5287     /* Hex 2D */
5288     depthSize[0] = vEnd - vStart + cEnd - cStart + fEnd - fStart; /* Add a vertex on every face and cell */
5289     depthSize[1] = 2*(fEnd - fStart) + 4*(cEnd - cStart);         /* Every face is split into 2 faces and 4 faces are added for each cell */
5290     depthSize[2] = 4*(cEnd - cStart);                             /* Every cell split into 4 cells */
5291     break;
5292   default:
5293     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5294   }
5295   PetscFunctionReturn(0);
5296 }
5297 
5298 #undef __FUNCT__
5299 #define __FUNCT__ "CellRefinerSetConeSizes"
5300 PetscErrorCode CellRefinerSetConeSizes(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5301 {
5302   PetscInt       depth, cStart, cStartNew, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fStartNew, fEnd, f, eStart, eStartNew, eEnd, r;
5303   PetscErrorCode ierr;
5304 
5305   PetscFunctionBegin;
5306   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5307   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5308   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5309   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5310   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5311   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5312   switch(refiner) {
5313   case 1:
5314     /* Simplicial 2D */
5315     /* All cells have 3 faces */
5316     for(c = cStart; c < cEnd; ++c) {
5317       for(r = 0; r < 4; ++r) {
5318         const PetscInt newp = (c - cStart)*4 + r;
5319 
5320         ierr = DMPlexSetConeSize(rdm, newp, 3);CHKERRQ(ierr);
5321       }
5322     }
5323     /* Split faces have 2 vertices and the same cells as the parent */
5324     for(f = fStart; f < fEnd; ++f) {
5325       for(r = 0; r < 2; ++r) {
5326         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5327         PetscInt       size;
5328 
5329         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5330         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5331         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5332       }
5333     }
5334     /* Interior faces have 2 vertices and 2 cells */
5335     for(c = cStart; c < cEnd; ++c) {
5336       for(r = 0; r < 3; ++r) {
5337         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5338 
5339         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5340         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5341       }
5342     }
5343     /* Old vertices have identical supports */
5344     for(v = vStart; v < vEnd; ++v) {
5345       const PetscInt newp = vStartNew + (v - vStart);
5346       PetscInt       size;
5347 
5348       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5349       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5350     }
5351     /* Face vertices have 2 + cells*2 supports */
5352     for(f = fStart; f < fEnd; ++f) {
5353       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5354       PetscInt       size;
5355 
5356       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5357       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size*2);CHKERRQ(ierr);
5358     }
5359     break;
5360   case 2:
5361     /* Hex 2D */
5362     /* All cells have 4 faces */
5363     for(c = cStart; c < cEnd; ++c) {
5364       for(r = 0; r < 4; ++r) {
5365         const PetscInt newp = (c - cStart)*4 + r;
5366 
5367         ierr = DMPlexSetConeSize(rdm, newp, 4);CHKERRQ(ierr);
5368       }
5369     }
5370     /* Split faces have 2 vertices and the same cells as the parent */
5371     for(f = fStart; f < fEnd; ++f) {
5372       for(r = 0; r < 2; ++r) {
5373         const PetscInt newp = fStartNew + (f - fStart)*2 + r;
5374         PetscInt       size;
5375 
5376         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5377         ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5378         ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5379       }
5380     }
5381     /* Interior faces have 2 vertices and 2 cells */
5382     for(c = cStart; c < cEnd; ++c) {
5383       for(r = 0; r < 4; ++r) {
5384         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5385 
5386         ierr = DMPlexSetConeSize(rdm, newp, 2);CHKERRQ(ierr);
5387         ierr = DMPlexSetSupportSize(rdm, newp, 2);CHKERRQ(ierr);
5388       }
5389     }
5390     /* Old vertices have identical supports */
5391     for(v = vStart; v < vEnd; ++v) {
5392       const PetscInt newp = vStartNew + (v - vStart);
5393       PetscInt       size;
5394 
5395       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5396       ierr = DMPlexSetSupportSize(rdm, newp, size);CHKERRQ(ierr);
5397     }
5398     /* Face vertices have 2 + cells supports */
5399     for(f = fStart; f < fEnd; ++f) {
5400       const PetscInt newp = vStartNew + (vEnd - vStart) + (f - fStart);
5401       PetscInt       size;
5402 
5403       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5404       ierr = DMPlexSetSupportSize(rdm, newp, 2 + size);CHKERRQ(ierr);
5405     }
5406     /* Cell vertices have 4 supports */
5407     for(c = cStart; c < cEnd; ++c) {
5408       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5409 
5410       ierr = DMPlexSetSupportSize(rdm, newp, 4);CHKERRQ(ierr);
5411     }
5412     break;
5413   default:
5414     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5415   }
5416   PetscFunctionReturn(0);
5417 }
5418 
5419 #undef __FUNCT__
5420 #define __FUNCT__ "CellRefinerSetCones"
5421 PetscErrorCode CellRefinerSetCones(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5422 {
5423   PetscInt       depth, cStart, cEnd, cStartNew, cEndNew, c, vStart, vEnd, vStartNew, vEndNew, v, fStart, fEnd, fStartNew, fEndNew, f, eStart, eEnd, eStartNew, eEndNew, r, p;
5424   PetscInt       maxSupportSize, *supportRef;
5425   PetscErrorCode ierr;
5426 
5427   PetscFunctionBegin;
5428   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5429   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5430   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
5431   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5432   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5433   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
5434   ierr = GetDepthEnd_Private(depth, depthSize, &cEndNew, &fEndNew, &eEndNew, &vEndNew);CHKERRQ(ierr);
5435   switch(refiner) {
5436   case 1:
5437     /* Simplicial 2D */
5438     /*
5439      2
5440      |\
5441      | \
5442      |  \
5443      |   \
5444      | C  \
5445      |     \
5446      |      \
5447      2---1---1
5448      |\  D  / \
5449      | 2   0   \
5450      |A \ /  B  \
5451      0---0-------1
5452      */
5453     /* All cells have 3 faces */
5454     for(c = cStart; c < cEnd; ++c) {
5455       const PetscInt  newp = (c - cStart)*4;
5456       const PetscInt *cone, *ornt;
5457       PetscInt        coneNew[3], orntNew[3];
5458 
5459       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5460       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5461       /* A triangle */
5462       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5463       orntNew[0] = ornt[0];
5464       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5465       orntNew[1] = -2;
5466       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5467       orntNew[2] = ornt[2];
5468       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5469       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5470 #if 1
5471       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);
5472       for(p = 0; p < 3; ++p) {
5473         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);
5474       }
5475 #endif
5476       /* B triangle */
5477       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5478       orntNew[0] = ornt[0];
5479       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5480       orntNew[1] = ornt[1];
5481       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5482       orntNew[2] = -2;
5483       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5484       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5485 #if 1
5486       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);
5487       for(p = 0; p < 3; ++p) {
5488         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);
5489       }
5490 #endif
5491       /* C triangle */
5492       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5493       orntNew[0] = -2;
5494       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5495       orntNew[1] = ornt[1];
5496       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5497       orntNew[2] = ornt[2];
5498       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5499       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5500 #if 1
5501       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);
5502       for(p = 0; p < 3; ++p) {
5503         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);
5504       }
5505 #endif
5506       /* D triangle */
5507       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 0;
5508       orntNew[0] = 0;
5509       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 1;
5510       orntNew[1] = 0;
5511       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*3 + 2;
5512       orntNew[2] = 0;
5513       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5514       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5515 #if 1
5516       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);
5517       for(p = 0; p < 3; ++p) {
5518         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);
5519       }
5520 #endif
5521     }
5522     /* Split faces have 2 vertices and the same cells as the parent */
5523     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5524     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5525     for(f = fStart; f < fEnd; ++f) {
5526       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5527 
5528       for(r = 0; r < 2; ++r) {
5529         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5530         const PetscInt *cone, *support;
5531         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5532 
5533         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5534         coneNew[0] = vStartNew + (cone[0] - vStart);
5535         coneNew[1] = vStartNew + (cone[1] - vStart);
5536         coneNew[(r+1)%2] = newv;
5537         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5538 #if 1
5539         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5540         for(p = 0; p < 2; ++p) {
5541           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);
5542         }
5543 #endif
5544         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5545         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5546         for(s = 0; s < supportSize; ++s) {
5547           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5548           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5549           for(c = 0; c < coneSize; ++c) {
5550             if (cone[c] == f) {
5551               break;
5552             }
5553           }
5554           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%3;
5555         }
5556         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5557 #if 1
5558         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5559         for(p = 0; p < supportSize; ++p) {
5560           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);
5561         }
5562 #endif
5563       }
5564     }
5565     /* Interior faces have 2 vertices and 2 cells */
5566     for(c = cStart; c < cEnd; ++c) {
5567       const PetscInt *cone;
5568 
5569       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5570       for(r = 0; r < 3; ++r) {
5571         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*3 + r;
5572         PetscInt       coneNew[2];
5573         PetscInt       supportNew[2];
5574 
5575         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r]       - fStart);
5576         coneNew[1] = vStartNew + (vEnd - vStart) + (cone[(r+1)%3] - fStart);
5577         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5578 #if 1
5579         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5580         for(p = 0; p < 2; ++p) {
5581           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);
5582         }
5583 #endif
5584         supportNew[0] = (c - cStart)*4 + r;
5585         supportNew[1] = (c - cStart)*4 + 3;
5586         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5587 #if 1
5588         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5589         for(p = 0; p < 2; ++p) {
5590           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);
5591         }
5592 #endif
5593       }
5594     }
5595     /* Old vertices have identical supports */
5596     for(v = vStart; v < vEnd; ++v) {
5597       const PetscInt  newp = vStartNew + (v - vStart);
5598       const PetscInt *support, *cone;
5599       PetscInt        size, s;
5600 
5601       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5602       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5603       for(s = 0; s < size; ++s) {
5604         PetscInt r = 0;
5605 
5606         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5607         if (cone[1] == v) r = 1;
5608         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5609       }
5610       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5611 #if 1
5612       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5613       for(p = 0; p < size; ++p) {
5614         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);
5615       }
5616 #endif
5617     }
5618     /* Face vertices have 2 + cells*2 supports */
5619     for(f = fStart; f < fEnd; ++f) {
5620       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5621       const PetscInt *cone, *support;
5622       PetscInt        size, s;
5623 
5624       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5625       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5626       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5627       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5628       for(s = 0; s < size; ++s) {
5629         PetscInt r = 0;
5630 
5631         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5632         if      (cone[1] == f) r = 1;
5633         else if (cone[2] == f) r = 2;
5634         supportRef[2+s*2+0] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + (r+2)%3;
5635         supportRef[2+s*2+1] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*3 + r;
5636       }
5637       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5638 #if 1
5639       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5640       for(p = 0; p < 2+size*2; ++p) {
5641         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);
5642       }
5643 #endif
5644     }
5645     ierr = PetscFree(supportRef);CHKERRQ(ierr);
5646     break;
5647   case 2:
5648     /* Hex 2D */
5649     /*
5650      3---------2---------2
5651      |         |         |
5652      |    D    2    C    |
5653      |         |         |
5654      3----3----0----1----1
5655      |         |         |
5656      |    A    0    B    |
5657      |         |         |
5658      0---------0---------1
5659      */
5660     /* All cells have 4 faces */
5661     for(c = cStart; c < cEnd; ++c) {
5662       const PetscInt  newp = (c - cStart)*4;
5663       const PetscInt *cone, *ornt;
5664       PetscInt        coneNew[4], orntNew[4];
5665 
5666       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5667       ierr = DMPlexGetConeOrientation(dm, c, &ornt);CHKERRQ(ierr);
5668       /* A quad */
5669       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 1 : 0);
5670       orntNew[0] = ornt[0];
5671       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5672       orntNew[1] = 0;
5673       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5674       orntNew[2] = -2;
5675       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 0 : 1);
5676       orntNew[3] = ornt[3];
5677       ierr = DMPlexSetCone(rdm, newp+0, coneNew);CHKERRQ(ierr);
5678       ierr = DMPlexSetConeOrientation(rdm, newp+0, orntNew);CHKERRQ(ierr);
5679 #if 1
5680       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);
5681       for(p = 0; p < 4; ++p) {
5682         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);
5683       }
5684 #endif
5685       /* B quad */
5686       coneNew[0] = fStartNew + (cone[0] - fStart)*2 + (ornt[0] < 0 ? 0 : 1);
5687       orntNew[0] = ornt[0];
5688       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 1 : 0);
5689       orntNew[1] = ornt[1];
5690       coneNew[2] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5691       orntNew[2] = 0;
5692       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 0;
5693       orntNew[3] = -2;
5694       ierr = DMPlexSetCone(rdm, newp+1, coneNew);CHKERRQ(ierr);
5695       ierr = DMPlexSetConeOrientation(rdm, newp+1, orntNew);CHKERRQ(ierr);
5696 #if 1
5697       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);
5698       for(p = 0; p < 4; ++p) {
5699         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);
5700       }
5701 #endif
5702       /* C quad */
5703       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 1;
5704       orntNew[0] = -2;
5705       coneNew[1] = fStartNew + (cone[1] - fStart)*2 + (ornt[1] < 0 ? 0 : 1);
5706       orntNew[1] = ornt[1];
5707       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 1 : 0);
5708       orntNew[2] = ornt[2];
5709       coneNew[3] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5710       orntNew[3] = 0;
5711       ierr = DMPlexSetCone(rdm, newp+2, coneNew);CHKERRQ(ierr);
5712       ierr = DMPlexSetConeOrientation(rdm, newp+2, orntNew);CHKERRQ(ierr);
5713 #if 1
5714       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);
5715       for(p = 0; p < 4; ++p) {
5716         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);
5717       }
5718 #endif
5719       /* D quad */
5720       coneNew[0] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 3;
5721       orntNew[0] = 0;
5722       coneNew[1] = fStartNew + (fEnd    - fStart)*2 + (c - cStart)*4 + 2;
5723       orntNew[1] = -2;
5724       coneNew[2] = fStartNew + (cone[2] - fStart)*2 + (ornt[2] < 0 ? 0 : 1);
5725       orntNew[2] = ornt[2];
5726       coneNew[3] = fStartNew + (cone[3] - fStart)*2 + (ornt[3] < 0 ? 1 : 0);
5727       orntNew[3] = ornt[3];
5728       ierr = DMPlexSetCone(rdm, newp+3, coneNew);CHKERRQ(ierr);
5729       ierr = DMPlexSetConeOrientation(rdm, newp+3, orntNew);CHKERRQ(ierr);
5730 #if 1
5731       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);
5732       for(p = 0; p < 4; ++p) {
5733         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);
5734       }
5735 #endif
5736     }
5737     /* Split faces have 2 vertices and the same cells as the parent */
5738     ierr = DMPlexGetMaxSizes(dm, PETSC_NULL, &maxSupportSize);CHKERRQ(ierr);
5739     ierr = PetscMalloc((2 + maxSupportSize*2) * sizeof(PetscInt), &supportRef);CHKERRQ(ierr);
5740     for(f = fStart; f < fEnd; ++f) {
5741       const PetscInt newv = vStartNew + (vEnd - vStart) + (f - fStart);
5742 
5743       for(r = 0; r < 2; ++r) {
5744         const PetscInt  newp = fStartNew + (f - fStart)*2 + r;
5745         const PetscInt *cone, *support;
5746         PetscInt        coneNew[2], coneSize, c, supportSize, s;
5747 
5748         ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5749         coneNew[0] = vStartNew + (cone[0] - vStart);
5750         coneNew[1] = vStartNew + (cone[1] - vStart);
5751         coneNew[(r+1)%2] = newv;
5752         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5753 #if 1
5754         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5755         for(p = 0; p < 2; ++p) {
5756           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);
5757         }
5758 #endif
5759         ierr = DMPlexGetSupportSize(dm, f, &supportSize);CHKERRQ(ierr);
5760         ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5761         for(s = 0; s < supportSize; ++s) {
5762           ierr = DMPlexGetConeSize(dm, support[s], &coneSize);CHKERRQ(ierr);
5763           ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5764           for(c = 0; c < coneSize; ++c) {
5765             if (cone[c] == f) {
5766               break;
5767             }
5768           }
5769           supportRef[s] = cStartNew + (support[s] - cStart)*4 + (c+r)%4;
5770         }
5771         ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5772 #if 1
5773         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5774         for(p = 0; p < supportSize; ++p) {
5775           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);
5776         }
5777 #endif
5778       }
5779     }
5780     /* Interior faces have 2 vertices and 2 cells */
5781     for(c = cStart; c < cEnd; ++c) {
5782       const PetscInt *cone;
5783       PetscInt        coneNew[2], supportNew[2];
5784 
5785       ierr = DMPlexGetCone(dm, c, &cone);CHKERRQ(ierr);
5786       for(r = 0; r < 4; ++r) {
5787         const PetscInt newp = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5788 
5789         coneNew[0] = vStartNew + (vEnd - vStart) + (cone[r] - fStart);
5790         coneNew[1] = vStartNew + (vEnd - vStart) + (fEnd    - fStart) + (c - cStart);
5791         ierr = DMPlexSetCone(rdm, newp, coneNew);CHKERRQ(ierr);
5792 #if 1
5793         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5794         for(p = 0; p < 2; ++p) {
5795           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);
5796         }
5797 #endif
5798         supportNew[0] = (c - cStart)*4 + r;
5799         supportNew[1] = (c - cStart)*4 + (r+1)%4;
5800         ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5801 #if 1
5802         if ((newp < fStartNew) || (newp >= fEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a face [%d, %d)", newp, fStartNew, fEndNew);
5803         for(p = 0; p < 2; ++p) {
5804           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);
5805         }
5806 #endif
5807       }
5808     }
5809     /* Old vertices have identical supports */
5810     for(v = vStart; v < vEnd; ++v) {
5811       const PetscInt  newp = vStartNew + (v - vStart);
5812       const PetscInt *support, *cone;
5813       PetscInt        size, s;
5814 
5815       ierr = DMPlexGetSupportSize(dm, v, &size);CHKERRQ(ierr);
5816       ierr = DMPlexGetSupport(dm, v, &support);CHKERRQ(ierr);
5817       for(s = 0; s < size; ++s) {
5818         PetscInt r = 0;
5819 
5820         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5821         if (cone[1] == v) r = 1;
5822         supportRef[s] = fStartNew + (support[s] - fStart)*2 + r;
5823       }
5824       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5825 #if 1
5826       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5827       for(p = 0; p < size; ++p) {
5828         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);
5829       }
5830 #endif
5831     }
5832     /* Face vertices have 2 + cells supports */
5833     for(f = fStart; f < fEnd; ++f) {
5834       const PetscInt  newp = vStartNew + (vEnd - vStart) + (f - fStart);
5835       const PetscInt *cone, *support;
5836       PetscInt        size, s;
5837 
5838       ierr = DMPlexGetSupportSize(dm, f, &size);CHKERRQ(ierr);
5839       ierr = DMPlexGetSupport(dm, f, &support);CHKERRQ(ierr);
5840       supportRef[0] = fStartNew + (f - fStart)*2 + 0;
5841       supportRef[1] = fStartNew + (f - fStart)*2 + 1;
5842       for(s = 0; s < size; ++s) {
5843         PetscInt r = 0;
5844 
5845         ierr = DMPlexGetCone(dm, support[s], &cone);CHKERRQ(ierr);
5846         if      (cone[1] == f) r = 1;
5847         else if (cone[2] == f) r = 2;
5848         else if (cone[3] == f) r = 3;
5849         supportRef[2+s] = fStartNew + (fEnd - fStart)*2 + (support[s] - cStart)*4 + r;
5850       }
5851       ierr = DMPlexSetSupport(rdm, newp, supportRef);CHKERRQ(ierr);
5852 #if 1
5853       if ((newp < vStartNew) || (newp >= vEndNew)) SETERRQ3(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Point %d is not a vertex [%d, %d)", newp, vStartNew, vEndNew);
5854       for(p = 0; p < 2+size; ++p) {
5855         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);
5856       }
5857 #endif
5858     }
5859     /* Cell vertices have 4 supports */
5860     for(c = cStart; c < cEnd; ++c) {
5861       const PetscInt newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5862       PetscInt       supportNew[4];
5863 
5864       for(r = 0; r < 4; ++r) {
5865         supportNew[r] = fStartNew + (fEnd - fStart)*2 + (c - cStart)*4 + r;
5866       }
5867       ierr = DMPlexSetSupport(rdm, newp, supportNew);CHKERRQ(ierr);
5868     }
5869     break;
5870   default:
5871     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5872   }
5873   PetscFunctionReturn(0);
5874 }
5875 
5876 #undef __FUNCT__
5877 #define __FUNCT__ "CellRefinerSetCoordinates"
5878 PetscErrorCode CellRefinerSetCoordinates(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
5879 {
5880   PetscSection   coordSection, coordSectionNew;
5881   Vec            coordinates, coordinatesNew;
5882   PetscScalar   *coords, *coordsNew;
5883   PetscInt       dim, depth, coordSizeNew, cStart, cEnd, c, vStart, vStartNew, vEnd, v, fStart, fEnd, f;
5884   PetscErrorCode ierr;
5885 
5886   PetscFunctionBegin;
5887   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
5888   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
5889   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
5890   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
5891   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
5892   ierr = GetDepthStart_Private(depth, depthSize, PETSC_NULL, PETSC_NULL, PETSC_NULL, &vStartNew);CHKERRQ(ierr);
5893   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
5894   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &coordSectionNew);CHKERRQ(ierr);
5895   ierr = PetscSectionSetNumFields(coordSectionNew, 1);CHKERRQ(ierr);
5896   ierr = PetscSectionSetFieldComponents(coordSectionNew, 0, dim);CHKERRQ(ierr);
5897   ierr = PetscSectionSetChart(coordSectionNew, vStartNew, vStartNew+depthSize[0]);CHKERRQ(ierr);
5898   switch(refiner) {
5899   case 1:
5900   case 2:
5901     /* Simplicial and Hex 2D */
5902     /* All vertices have the dim coordinates */
5903     for(v = vStartNew; v < vStartNew+depthSize[0]; ++v) {
5904       ierr = PetscSectionSetDof(coordSectionNew, v, dim);CHKERRQ(ierr);
5905       ierr = PetscSectionSetFieldDof(coordSectionNew, v, 0, dim);CHKERRQ(ierr);
5906     }
5907     ierr = PetscSectionSetUp(coordSectionNew);CHKERRQ(ierr);
5908     ierr = DMPlexSetCoordinateSection(rdm, coordSectionNew);CHKERRQ(ierr);
5909     ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
5910     ierr = PetscSectionGetStorageSize(coordSectionNew, &coordSizeNew);CHKERRQ(ierr);
5911     ierr = VecCreate(((PetscObject) dm)->comm, &coordinatesNew);CHKERRQ(ierr);
5912     ierr = PetscObjectSetName((PetscObject) coordinatesNew, "coordinates");CHKERRQ(ierr);
5913     ierr = VecSetSizes(coordinatesNew, coordSizeNew, PETSC_DETERMINE);CHKERRQ(ierr);
5914     ierr = VecSetFromOptions(coordinatesNew);CHKERRQ(ierr);
5915     ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
5916     ierr = VecGetArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5917     /* Old vertices have the same coordinates */
5918     for(v = vStart; v < vEnd; ++v) {
5919       const PetscInt newv = vStartNew + (v - vStart);
5920       PetscInt       off, offnew, d;
5921 
5922       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
5923       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5924       for(d = 0; d < dim; ++d) {
5925         coordsNew[offnew+d] = coords[off+d];
5926       }
5927     }
5928     /* Face vertices have the average of endpoint coordinates */
5929     for(f = fStart; f < fEnd; ++f) {
5930       const PetscInt  newv = vStartNew + (vEnd - vStart) + (f - fStart);
5931       const PetscInt *cone;
5932       PetscInt        coneSize, offA, offB, offnew, d;
5933 
5934       ierr = DMPlexGetConeSize(dm, f, &coneSize);CHKERRQ(ierr);
5935       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Face %d cone should have two vertices, not %d", f, coneSize);
5936       ierr = DMPlexGetCone(dm, f, &cone);CHKERRQ(ierr);
5937       ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5938       ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5939       ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5940       for(d = 0; d < dim; ++d) {
5941         coordsNew[offnew+d] = 0.5*(coords[offA+d] + coords[offB+d]);
5942       }
5943     }
5944     /* Just Hex 2D */
5945     if (refiner == 2) {
5946       /* Cell vertices have the average of corner coordinates */
5947       for(c = cStart; c < cEnd; ++c) {
5948         const PetscInt newv = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (c - cStart);
5949         PetscInt      *cone = PETSC_NULL;
5950         PetscInt       closureSize, coneSize = 0, offA, offB, offC, offD, offnew, p, d;
5951 
5952         ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5953         for(p = 0; p < closureSize*2; p += 2) {
5954           const PetscInt point = cone[p];
5955           if ((point >= vStart) && (point < vEnd)) {
5956             cone[coneSize++] = point;
5957           }
5958         }
5959         if (coneSize != 4) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Quad %d cone should have four vertices, not %d", c, coneSize);
5960         ierr = PetscSectionGetOffset(coordSection, cone[0], &offA);CHKERRQ(ierr);
5961         ierr = PetscSectionGetOffset(coordSection, cone[1], &offB);CHKERRQ(ierr);
5962         ierr = PetscSectionGetOffset(coordSection, cone[2], &offC);CHKERRQ(ierr);
5963         ierr = PetscSectionGetOffset(coordSection, cone[3], &offD);CHKERRQ(ierr);
5964         ierr = PetscSectionGetOffset(coordSectionNew, newv, &offnew);CHKERRQ(ierr);
5965         for(d = 0; d < dim; ++d) {
5966           coordsNew[offnew+d] = 0.25*(coords[offA+d] + coords[offB+d] + coords[offC+d] + coords[offD+d]);
5967         }
5968         ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &cone);CHKERRQ(ierr);
5969       }
5970     }
5971     ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
5972     ierr = VecRestoreArray(coordinatesNew, &coordsNew);CHKERRQ(ierr);
5973     ierr = DMSetCoordinatesLocal(rdm, coordinatesNew);CHKERRQ(ierr);
5974     ierr = VecDestroy(&coordinatesNew);CHKERRQ(ierr);
5975     break;
5976   default:
5977     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
5978   }
5979   PetscFunctionReturn(0);
5980 }
5981 
5982 #undef __FUNCT__
5983 #define __FUNCT__ "DMPlexCreateProcessSF"
5984 PetscErrorCode DMPlexCreateProcessSF(DM dm, PetscSF sfPoint, IS *processRanks, PetscSF *sfProcess)
5985 {
5986   PetscInt           numRoots, numLeaves, l;
5987   const PetscInt    *localPoints;
5988   const PetscSFNode *remotePoints;
5989   PetscInt          *localPointsNew;
5990   PetscSFNode       *remotePointsNew;
5991   PetscInt          *ranks, *ranksNew;
5992   PetscErrorCode     ierr;
5993 
5994   PetscFunctionBegin;
5995   ierr = PetscSFGetGraph(sfPoint, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
5996   ierr = PetscMalloc(numLeaves * sizeof(PetscInt), &ranks);CHKERRQ(ierr);
5997   for(l = 0; l < numLeaves; ++l) {
5998     ranks[l] = remotePoints[l].rank;
5999   }
6000   ierr = PetscSortRemoveDupsInt(&numLeaves, ranks);CHKERRQ(ierr);
6001   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &ranksNew);CHKERRQ(ierr);
6002   ierr = PetscMalloc(numLeaves * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6003   ierr = PetscMalloc(numLeaves * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6004   for(l = 0; l < numLeaves; ++l) {
6005     ranksNew[l]              = ranks[l];
6006     localPointsNew[l]        = l;
6007     remotePointsNew[l].index = 0;
6008     remotePointsNew[l].rank  = ranksNew[l];
6009   }
6010   ierr = PetscFree(ranks);CHKERRQ(ierr);
6011   ierr = ISCreateGeneral(((PetscObject) dm)->comm, numLeaves, ranksNew, PETSC_OWN_POINTER, processRanks);CHKERRQ(ierr);
6012   ierr = PetscSFCreate(((PetscObject) dm)->comm, sfProcess);CHKERRQ(ierr);
6013   ierr = PetscSFSetFromOptions(*sfProcess);CHKERRQ(ierr);
6014   ierr = PetscSFSetGraph(*sfProcess, 1, numLeaves, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6015   PetscFunctionReturn(0);
6016 }
6017 
6018 #undef __FUNCT__
6019 #define __FUNCT__ "CellRefinerCreateSF"
6020 PetscErrorCode CellRefinerCreateSF(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6021 {
6022   PetscSF            sf, sfNew, sfProcess;
6023   IS                 processRanks;
6024   MPI_Datatype       depthType;
6025   PetscInt           numRoots, numLeaves, numLeavesNew = 0, l, m;
6026   const PetscInt    *localPoints, *neighbors;
6027   const PetscSFNode *remotePoints;
6028   PetscInt          *localPointsNew;
6029   PetscSFNode       *remotePointsNew;
6030   PetscInt          *depthSizeOld, *rdepthSize, *rdepthSizeOld, *rvStart, *rvStartNew, *reStart, *reStartNew, *rfStart, *rfStartNew, *rcStart, *rcStartNew;
6031   PetscInt           depth, numNeighbors, pStartNew, pEndNew, cStart, cStartNew, cEnd, vStart, vStartNew, vEnd, fStart, fStartNew, fEnd, eStart, eStartNew, eEnd, r, n;
6032   PetscErrorCode     ierr;
6033 
6034   PetscFunctionBegin;
6035   ierr = DMPlexGetChart(rdm, &pStartNew, &pEndNew);CHKERRQ(ierr);
6036   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6037   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6038   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6039   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6040   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6041   ierr = GetDepthStart_Private(depth, depthSize, &cStartNew, &fStartNew, &eStartNew, &vStartNew);CHKERRQ(ierr);
6042   ierr = DMGetPointSF(dm, &sf);CHKERRQ(ierr);
6043   ierr = DMGetPointSF(rdm, &sfNew);CHKERRQ(ierr);
6044   /* Caculate size of new SF */
6045   ierr = PetscSFGetGraph(sf, &numRoots, &numLeaves, &localPoints, &remotePoints);CHKERRQ(ierr);
6046   if (numRoots < 0) PetscFunctionReturn(0);
6047   for(l = 0; l < numLeaves; ++l) {
6048     const PetscInt p = localPoints[l];
6049 
6050     switch(refiner) {
6051     case 1:
6052       /* Simplicial 2D */
6053       if ((p >= vStart) && (p < vEnd)) {
6054         /* Old vertices stay the same */
6055         ++numLeavesNew;
6056       } else if ((p >= fStart) && (p < fEnd)) {
6057         /* Old faces add new faces and vertex */
6058         numLeavesNew += 1 + 2;
6059       } else if ((p >= cStart) && (p < cEnd)) {
6060         /* Old cells add new cells and interior faces */
6061         numLeavesNew += 4 + 3;
6062       }
6063       break;
6064     case 2:
6065       /* Hex 2D */
6066       if ((p >= vStart) && (p < vEnd)) {
6067         /* Old vertices stay the same */
6068         ++numLeavesNew;
6069       } else if ((p >= fStart) && (p < fEnd)) {
6070         /* Old faces add new faces and vertex */
6071         numLeavesNew += 1 + 2;
6072       } else if ((p >= cStart) && (p < cEnd)) {
6073         /* Old cells add new cells and interior faces */
6074         numLeavesNew += 4 + 4;
6075       }
6076       break;
6077     default:
6078       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6079     }
6080   }
6081   /* Communicate depthSizes for each remote rank */
6082   ierr = DMPlexCreateProcessSF(dm, sf, &processRanks, &sfProcess);CHKERRQ(ierr);
6083   ierr = ISGetLocalSize(processRanks, &numNeighbors);CHKERRQ(ierr);
6084   ierr = PetscMalloc5((depth+1)*numNeighbors,PetscInt,&rdepthSize,numNeighbors,PetscInt,&rvStartNew,numNeighbors,PetscInt,&reStartNew,numNeighbors,PetscInt,&rfStartNew,numNeighbors,PetscInt,&rcStartNew);CHKERRQ(ierr);
6085   ierr = PetscMalloc6(depth+1,PetscInt,&depthSizeOld,(depth+1)*numNeighbors,PetscInt,&rdepthSizeOld,numNeighbors,PetscInt,&rvStart,numNeighbors,PetscInt,&reStart,numNeighbors,PetscInt,&rfStart,numNeighbors,PetscInt,&rcStart);CHKERRQ(ierr);
6086   ierr = MPI_Type_contiguous(depth+1, MPIU_INT, &depthType);CHKERRQ(ierr);
6087   ierr = MPI_Type_commit(&depthType);CHKERRQ(ierr);
6088   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6089   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSize, rdepthSize);CHKERRQ(ierr);
6090   for(n = 0; n < numNeighbors; ++n) {
6091     ierr = GetDepthStart_Private(depth, &rdepthSize[n*(depth+1)], &rcStartNew[n], &rfStartNew[n], &reStartNew[n], &rvStartNew[n]);CHKERRQ(ierr);
6092   }
6093   depthSizeOld[depth]   = cEnd - cStart;
6094   depthSizeOld[0]       = vEnd - vStart;
6095   depthSizeOld[depth-1] = fEnd - fStart;
6096   depthSizeOld[1]       = eEnd - eStart;
6097   ierr = PetscSFBcastBegin(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6098   ierr = PetscSFBcastEnd(sfProcess, depthType, depthSizeOld, rdepthSizeOld);CHKERRQ(ierr);
6099   for(n = 0; n < numNeighbors; ++n) {
6100     ierr = GetDepthStart_Private(depth, &rdepthSizeOld[n*(depth+1)], &rcStart[n], &rfStart[n], &reStart[n], &rvStart[n]);CHKERRQ(ierr);
6101   }
6102   ierr = MPI_Type_free(&depthType);CHKERRQ(ierr);
6103   ierr = PetscSFDestroy(&sfProcess);CHKERRQ(ierr);
6104   /* Calculate new point SF */
6105   ierr = PetscMalloc(numLeavesNew * sizeof(PetscInt),    &localPointsNew);CHKERRQ(ierr);
6106   ierr = PetscMalloc(numLeavesNew * sizeof(PetscSFNode), &remotePointsNew);CHKERRQ(ierr);
6107   ierr = ISGetIndices(processRanks, &neighbors);CHKERRQ(ierr);
6108   for(l = 0, m = 0; l < numLeaves; ++l) {
6109     PetscInt    p     = localPoints[l];
6110     PetscInt    rp    = remotePoints[l].index, n;
6111     PetscMPIInt rrank = remotePoints[l].rank;
6112 
6113     ierr = PetscFindInt(rrank, numNeighbors, neighbors, &n);CHKERRQ(ierr);
6114     if (n < 0) SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Could not locate remote rank %d", rrank);
6115     switch(refiner) {
6116     case 1:
6117       /* Simplicial 2D */
6118       if ((p >= vStart) && (p < vEnd)) {
6119         /* Old vertices stay the same */
6120         localPointsNew[m]        = vStartNew     + (p  - vStart);
6121         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6122         remotePointsNew[m].rank  = rrank;
6123         ++m;
6124       } else if ((p >= fStart) && (p < fEnd)) {
6125         /* Old faces add new faces and vertex */
6126         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6127         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6128         remotePointsNew[m].rank  = rrank;
6129         ++m;
6130         for(r = 0; r < 2; ++r, ++m) {
6131           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6132           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6133           remotePointsNew[m].rank  = rrank;
6134         }
6135       } else if ((p >= cStart) && (p < cEnd)) {
6136         /* Old cells add new cells and interior faces */
6137         for(r = 0; r < 4; ++r, ++m) {
6138           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6139           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6140           remotePointsNew[m].rank  = rrank;
6141         }
6142         for(r = 0; r < 3; ++r, ++m) {
6143           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*3     + r;
6144           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*3 + r;
6145           remotePointsNew[m].rank  = rrank;
6146         }
6147       }
6148       break;
6149     case 2:
6150       /* Hex 2D */
6151       if ((p >= vStart) && (p < vEnd)) {
6152         /* Old vertices stay the same */
6153         localPointsNew[m]        = vStartNew     + (p  - vStart);
6154         remotePointsNew[m].index = rvStartNew[n] + (rp - rvStart[n]);
6155         remotePointsNew[m].rank  = rrank;
6156         ++m;
6157       } else if ((p >= fStart) && (p < fEnd)) {
6158         /* Old faces add new faces and vertex */
6159         localPointsNew[m]        = vStartNew     + (vEnd - vStart)              + (p  - fStart);
6160         remotePointsNew[m].index = rvStartNew[n] + rdepthSizeOld[n*(depth+1)+0] + (rp - rfStart[n]);
6161         remotePointsNew[m].rank  = rrank;
6162         ++m;
6163         for(r = 0; r < 2; ++r, ++m) {
6164           localPointsNew[m]        = fStartNew     + (p  - fStart)*2     + r;
6165           remotePointsNew[m].index = rfStartNew[n] + (rp - rfStart[n])*2 + r;
6166           remotePointsNew[m].rank  = rrank;
6167         }
6168       } else if ((p >= cStart) && (p < cEnd)) {
6169         /* Old cells add new cells and interior faces */
6170         for(r = 0; r < 4; ++r, ++m) {
6171           localPointsNew[m]        = cStartNew     + (p  - cStart)*4     + r;
6172           remotePointsNew[m].index = rcStartNew[n] + (rp - rcStart[n])*4 + r;
6173           remotePointsNew[m].rank  = rrank;
6174         }
6175         for(r = 0; r < 4; ++r, ++m) {
6176           localPointsNew[m]        = fStartNew     + (fEnd - fStart)*2                    + (p  - cStart)*4     + r;
6177           remotePointsNew[m].index = rfStartNew[n] + rdepthSizeOld[n*(depth+1)+depth-1]*2 + (rp - rcStart[n])*4 + r;
6178           remotePointsNew[m].rank  = rrank;
6179         }
6180       }
6181       break;
6182     default:
6183       SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6184     }
6185   }
6186   ierr = ISRestoreIndices(processRanks, &neighbors);CHKERRQ(ierr);
6187   ierr = ISDestroy(&processRanks);CHKERRQ(ierr);
6188   ierr = PetscSFSetGraph(sfNew, pEndNew-pStartNew, numLeavesNew, localPointsNew, PETSC_OWN_POINTER, remotePointsNew, PETSC_OWN_POINTER);CHKERRQ(ierr);
6189   ierr = PetscFree5(rdepthSize,rvStartNew,reStartNew,rfStartNew,rcStartNew);CHKERRQ(ierr);
6190   ierr = PetscFree6(depthSizeOld,rdepthSizeOld,rvStart,reStart,rfStart,rcStart);CHKERRQ(ierr);
6191   PetscFunctionReturn(0);
6192 }
6193 
6194 #undef __FUNCT__
6195 #define __FUNCT__ "CellRefinerCreateLabels"
6196 PetscErrorCode CellRefinerCreateLabels(CellRefiner refiner, DM dm, PetscInt depthSize[], DM rdm)
6197 {
6198   PetscInt       numLabels, l;
6199   PetscInt       newp, cStart, cEnd, vStart, vStartNew, vEnd, fStart, fStartNew, fEnd, eStart, eEnd, r;
6200   PetscErrorCode ierr;
6201 
6202   PetscFunctionBegin;
6203   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6204   ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);
6205   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6206   ierr = DMPlexGetHeightStratum(dm, 1, &fStart, &fEnd);CHKERRQ(ierr);
6207   vStartNew = depthSize[2];
6208   fStartNew = depthSize[2] + depthSize[0];
6209   ierr = DMPlexGetNumLabels(dm, &numLabels);CHKERRQ(ierr);
6210   for(l = 0; l < numLabels; ++l) {
6211     DMLabel         label, labelNew;
6212     const char     *lname;
6213     PetscBool       isDepth;
6214     IS              valueIS;
6215     const PetscInt *values;
6216     PetscInt        numValues, val;
6217 
6218     ierr = DMPlexGetLabelName(dm, l, &lname);CHKERRQ(ierr);
6219     ierr = PetscStrcmp(lname, "depth", &isDepth);CHKERRQ(ierr);
6220     if (isDepth) continue;
6221     ierr = DMPlexCreateLabel(rdm, lname);CHKERRQ(ierr);
6222     ierr = DMPlexGetLabel(dm, lname, &label);CHKERRQ(ierr);
6223     ierr = DMPlexGetLabel(rdm, lname, &labelNew);CHKERRQ(ierr);
6224     ierr = DMLabelGetValueIS(label, &valueIS);CHKERRQ(ierr);
6225     ierr = ISGetLocalSize(valueIS, &numValues);CHKERRQ(ierr);
6226     ierr = ISGetIndices(valueIS, &values);CHKERRQ(ierr);
6227     for(val = 0; val < numValues; ++val) {
6228       IS              pointIS;
6229       const PetscInt *points;
6230       PetscInt        numPoints, n;
6231 
6232       ierr = DMLabelGetStratumIS(label, values[val], &pointIS);CHKERRQ(ierr);
6233       ierr = ISGetLocalSize(pointIS, &numPoints);CHKERRQ(ierr);
6234       ierr = ISGetIndices(pointIS, &points);CHKERRQ(ierr);
6235       for(n = 0; n < numPoints; ++n) {
6236         const PetscInt p = points[n];
6237         switch(refiner) {
6238         case 1:
6239           /* Simplicial 2D */
6240           if ((p >= vStart) && (p < vEnd)) {
6241             /* Old vertices stay the same */
6242             newp = vStartNew + (p - vStart);
6243             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6244           } else if ((p >= fStart) && (p < fEnd)) {
6245             /* Old faces add new faces and vertex */
6246             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6247             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6248             for(r = 0; r < 2; ++r) {
6249               newp = fStartNew + (p - fStart)*2 + r;
6250               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6251             }
6252           } else if ((p >= cStart) && (p < cEnd)) {
6253             /* Old cells add new cells and interior faces */
6254             for(r = 0; r < 4; ++r) {
6255               newp = (p - cStart)*4 + r;
6256               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6257             }
6258             for(r = 0; r < 3; ++r) {
6259               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*3 + r;
6260               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6261             }
6262           }
6263           break;
6264         case 2:
6265           /* Hex 2D */
6266           if ((p >= vStart) && (p < vEnd)) {
6267             /* Old vertices stay the same */
6268             newp = vStartNew + (p - vStart);
6269             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6270           } else if ((p >= fStart) && (p < fEnd)) {
6271             /* Old faces add new faces and vertex */
6272             newp = vStartNew + (vEnd - vStart) + (p - fStart);
6273             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6274             for(r = 0; r < 2; ++r) {
6275               newp = fStartNew + (p - fStart)*2 + r;
6276               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6277             }
6278           } else if ((p >= cStart) && (p < cEnd)) {
6279             /* Old cells add new cells and interior faces and vertex */
6280             for(r = 0; r < 4; ++r) {
6281               newp = (p - cStart)*4 + r;
6282               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6283             }
6284             for(r = 0; r < 4; ++r) {
6285               newp = fStartNew + (fEnd - fStart)*2 + (p - cStart)*4 + r;
6286               ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6287             }
6288             newp = vStartNew + (vEnd - vStart) + (fEnd - fStart) + (p - cStart);
6289             ierr = DMLabelSetValue(labelNew, newp, values[val]);CHKERRQ(ierr);
6290           }
6291           break;
6292         default:
6293           SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown cell refiner %d", refiner);
6294         }
6295       }
6296       ierr = ISRestoreIndices(pointIS, &points);CHKERRQ(ierr);
6297       ierr = ISDestroy(&pointIS);CHKERRQ(ierr);
6298     }
6299     ierr = ISRestoreIndices(valueIS, &values);CHKERRQ(ierr);
6300     ierr = ISDestroy(&valueIS);CHKERRQ(ierr);
6301     if (0) {
6302       ierr = PetscViewerASCIISynchronizedAllow(PETSC_VIEWER_STDOUT_WORLD, PETSC_TRUE);CHKERRQ(ierr);
6303       ierr = DMLabelView(labelNew, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6304       ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
6305     }
6306   }
6307   PetscFunctionReturn(0);
6308 }
6309 
6310 #undef __FUNCT__
6311 #define __FUNCT__ "DMPlexRefine_Uniform"
6312 /* This will only work for interpolated meshes */
6313 PetscErrorCode DMPlexRefine_Uniform(DM dm, CellRefiner cellRefiner, DM *dmRefined)
6314 {
6315   DM              rdm;
6316   PetscInt       *depthSize;
6317   PetscInt        dim, depth = 0, d, pStart = 0, pEnd = 0;
6318   PetscErrorCode  ierr;
6319 
6320   PetscFunctionBegin;
6321   ierr = DMCreate(((PetscObject) dm)->comm, &rdm);CHKERRQ(ierr);
6322   ierr = DMSetType(rdm, DMPLEX);CHKERRQ(ierr);
6323   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6324   ierr = DMPlexSetDimension(rdm, dim);CHKERRQ(ierr);
6325   /* Calculate number of new points of each depth */
6326   ierr = DMPlexGetDepth(dm, &depth);CHKERRQ(ierr);
6327   ierr = PetscMalloc((depth+1) * sizeof(PetscInt), &depthSize);CHKERRQ(ierr);
6328   ierr = PetscMemzero(depthSize, (depth+1) * sizeof(PetscInt));CHKERRQ(ierr);
6329   ierr = CellRefinerGetSizes(cellRefiner, dm, depthSize);CHKERRQ(ierr);
6330   /* Step 1: Set chart */
6331   for(d = 0; d <= depth; ++d) {
6332     pEnd += depthSize[d];
6333   }
6334   ierr = DMPlexSetChart(rdm, pStart, pEnd);CHKERRQ(ierr);
6335   /* Step 2: Set cone/support sizes */
6336   ierr = CellRefinerSetConeSizes(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6337   /* Step 3: Setup refined DM */
6338   ierr = DMSetUp(rdm);CHKERRQ(ierr);
6339   /* Step 4: Set cones and supports */
6340   ierr = CellRefinerSetCones(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6341   /* Step 5: Stratify */
6342   ierr = DMPlexStratify(rdm);CHKERRQ(ierr);
6343   /* Step 6: Set coordinates for vertices */
6344   ierr = CellRefinerSetCoordinates(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6345   /* Step 7: Create pointSF */
6346   ierr = CellRefinerCreateSF(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6347   /* Step 8: Create labels */
6348   ierr = CellRefinerCreateLabels(cellRefiner, dm, depthSize, rdm);CHKERRQ(ierr);
6349   ierr = PetscFree(depthSize);CHKERRQ(ierr);
6350 
6351   *dmRefined = rdm;
6352 #if 0
6353   DM_Plex *mesh = (DM_Plex *) dm->data;
6354   PetscInt    dim, cStart, cEnd, cMax, c, vStart, vEnd, vMax;
6355   //ALE::ISieveVisitor::PointRetriever<mesh_type::sieve_type> cV(std::max(1, sieve->getMaxConeSize()));
6356 
6357   PetscFunctionBegin;
6358   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6359   /* PyLith: _refineCensored(newMesh, mesh, refiner); */
6360   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6361   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
6362   ierr = DMPlexGetVTKBounds(dm, &cMax, &vMax);CHKERRQ(ierr);
6363 
6364   /* Count number of new cells which are normal and extra */
6365   PetscInt cEnd2 = cMax >= 0 ? cMax : cEnd;
6366   PetscInt newNumCellsNormal = 0, newNumCellsExtra = 0, newNumCells;
6367   for(c = cStart; c < cEnd2; ++c) {
6368     PetscInt n;
6369     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); // refiner.numNewCells
6370     newNumCellsNormal += n;
6371   }
6372   for(c = cEnd2; c < cEnd; ++c) {
6373     PetscInt n;
6374     ierr = CellRefinerGetNumSubcells(c, &n);CHKERRQ(ierr); // refiner.numNewCells
6375     newNumCellsExtra += n;
6376   }
6377   newNumCells = newNumCellsNormal + newNumCellsExtra;
6378   /* Count number of new vertices which are normal and extra */
6379   PetscInt vEnd2 = vMax >= 0 ? vMax : vEnd;
6380   PetscInt newNumVertices, newNumVerticesNormal, newNumVerticesExtra, newFirstVertex = newNumCells + (vEnd2 - vStart), newVertex = newFirstVertex;
6381   for(c = cStart; c < cEnd; ++c) {
6382     PetscInt *closure = PETSC_NULL;
6383     PetscInt  closureSize, numCorners = 0, p;
6384 
6385     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6386     for(p = 0; p < closureSize*2; p += 2) {
6387       const PetscInt point = closure[p];
6388       if ((point >= vStart) && (point < vEnd)) {
6389         closure[numCorners++] = point;
6390       }
6391     }
6392     ierr = CellRefinerSplitCell(c, closure, numCorners, &newVertex);CHKERRQ(ierr); // refiner.splitCell
6393     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6394   }
6395   newNumVerticesNormal = newVertex - newFirstVertex + (vEnd2 - vStart);
6396   for(c = cEnd2; c < cEnd; ++c) {
6397     PetscInt *closure = PETSC_NULL;
6398     PetscInt  closureSize, numCorners = 0, p;
6399 
6400     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6401     for(p = 0; p < closureSize*2; p += 2) {
6402       const PetscInt point = closure[p];
6403       if ((point >= vStart) && (point < vEnd)) {
6404         closure[numCorners++] = point;
6405       }
6406     }
6407     ierr = CellRefinerSplitCellExtra(c, closure, numCorners, &newVertex);CHKERRQ(ierr); // refiner.splitCellUncensored
6408     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6409   } // for
6410   newNumVerticesExtra = newVertex - newFirstVertex - newNumVerticesNormal;
6411   newNumVertices = newNumVerticesNormal + newNumVerticesExtra;
6412 
6413 #if 1
6414   PetscInt oldNumCellsNormal   = cEnd2 - cStart;
6415   PetscInt oldNumCellsExtra = cEnd  - cEnd2;
6416   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal cells    [%d, %d)\n", rank, 0, oldNumCellsNormal);
6417   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  cells    [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra+oldNumCellsExtra);
6418   ierr = PetscSynchronizedPrintf(comm, "[%d]Old normal vertices [%d, %d)\n", rank, oldNumCellsNormal, oldNumCellsNormal+oldNumVerticesNormal);
6419   ierr = PetscSynchronizedPrintf(comm, "[%d]Old fault  vertices [%d, %d)\n", rank, oldNumCellsNormal+oldNumVerticesNormal, oldNumCellsNormal+oldNumVerticesNormal+oldNumVerticesExtra);
6420   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal cells    [%d, %d)\n", rank, 0, newNumCellsNormal);
6421   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  cells    [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra+newNumCellsExtra);
6422   ierr = PetscSynchronizedPrintf(comm, "[%d]New normal vertices [%d, %d)\n", rank, newNumCellsNormal, newNumCellsNormal+newNumVerticesNormal);
6423   ierr = PetscSynchronizedPrintf(comm, "[%d]New fault  vertices [%d, %d)\n", rank, newNumCellsNormal+newNumVerticesNormal, newNumCellsNormal+newNumVerticesNormal+newNumVerticesExtra);
6424   ierr = PetscSynchronizedFlush(comm);
6425 #endif
6426 
6427   ierr = DMCreate(comm, dmRefined);CHKERRQ(ierr);
6428   ierr = DMSetType(*dmRefined, DMPLEX);CHKERRQ(ierr);
6429   ierr = DMPlexSetDimension(*dm, dim);CHKERRQ(ierr);
6430   ierr = DMPlexSetChart(*dmRefined, 0, newNumCells+newNumVertices);CHKERRQ(ierr);
6431   ierr = DMPlexGetVTKBounds(*dmRefined, newNumCellsNormal, newFirstVertex+newNumVerticesNormal);CHKERRQ(ierr);
6432   /* Set cone and support sizes for new normal cells */
6433   PetscInt newCell = 0;
6434   for(c = cStart; c < cEnd2; ++c) {
6435     PetscInt coneSize, n, i;
6436 
6437     ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
6438     ierr = CellRefinerGetNumSubcells(refiner, c, &n); // refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6439     for(i = 0; i < n; ++i, ++newCell) {
6440       ierr = DMPlexSetConeSize(*dmRefined, newCell, coneSize);CHKERRQ(ierr);
6441     }
6442 
6443     PetscInt *closure = PETSC_NULL;
6444     PetscInt  closureSize, numCorners = 0, p;
6445 
6446     ierr = DMPlexGetTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6447     for(p = 0; p < closureSize*2; p += 2) {
6448       const PetscInt point = closure[p];
6449       if ((point >= vStart) && (point < vEnd)) {
6450         closure[numCorners++] = point;
6451       }
6452     }
6453     // ierr = CellRefinerGetSubcells(refiner, c, numCorners, closure, &numNewCells, &newCells);CHKERRQ(ierr); // refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6454     ierr = DMPlexRestoreTransitiveClosure(dm, c, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
6455   }
6456 
6457   // Reset current new cell value and loop over censored cells.
6458   curNewCell = _orderNewMesh->cellsCensored().min();
6459   oldCellsEnd = _orderOldMesh->cellsCensored().end();
6460   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
6461     // Set new cone and support sizes
6462     cV.clear();
6463     sieve->cone(*c_iter, cV);
6464     const point_type* cone = cV.getPoints();
6465     const int coneSize = cV.getSize();
6466 
6467     const point_type* newCells;
6468     int numNewCells = 0;
6469     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6470 
6471     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
6472       newSieve->setConeSize(curNewCell, coneSize);
6473       for(int iVertex=0; iVertex < coneSize; ++iVertex) {
6474 	newSieve->addSupportSize(newCells[iCell*coneSize+iVertex], 1);
6475       } // for
6476     } // for
6477   } // for
6478   newSieve->allocate();
6479 
6480   ierr = DMPlexSymmetrizeSizes();CHKERRQ(ierr);
6481 
6482   // Create refined cells in new sieve.
6483   curNewCell = _orderNewMesh->cellsNormal().min();
6484   oldCellsEnd = _orderOldMesh->cellsNormal().end();
6485   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsNormal().begin(); c_iter != oldCellsEnd; ++c_iter) {
6486     cV.clear();
6487     sieve->cone(*c_iter, cV);
6488     const point_type *cone = cV.getPoints();
6489     const int coneSize = cV.getSize();
6490 
6491     const point_type* newCells;
6492     int numNewCells = 0;
6493     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6494 
6495     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
6496       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
6497     } // for
6498   } // for
6499   curNewCell = _orderNewMesh->cellsCensored().min();
6500   oldCellsEnd = _orderOldMesh->cellsCensored().end();
6501   for (interval_type::const_iterator c_iter=_orderOldMesh->cellsCensored().begin(); c_iter != oldCellsEnd; ++c_iter) {
6502     cV.clear();
6503     sieve->cone(*c_iter, cV);
6504     const point_type *cone = cV.getPoints();
6505     const int coneSize = cV.getSize();
6506 
6507     const point_type* newCells;
6508     int numNewCells = 0;
6509     refiner.getNewCells(&newCells, &numNewCells, *c_iter, cone, coneSize, *_orderOldMesh, *_orderNewMesh);
6510 
6511     for(int iCell=0; iCell < numNewCells; ++iCell, ++curNewCell) {
6512       newSieve->setCone(&newCells[iCell*coneSize], curNewCell);
6513     } // for
6514   } // for
6515   newSieve->symmetrize();
6516 
6517   // Set coordinates in refined mesh.
6518   const Obj<mesh_type::real_section_type>& coordinates = mesh->getRealSection("coordinates");
6519   assert(!coordinates.isNull());
6520   const Obj<mesh_type::real_section_type>& newCoordinates = newMesh->getRealSection("coordinates");
6521   assert(!newCoordinates.isNull());
6522 
6523   const mesh_type::label_sequence::const_iterator verticesEnd = vertices->end();
6524   assert(vertices->size() > 0);
6525   const int spaceDim = coordinates->getFiberDimension(*vertices->begin());
6526   assert(spaceDim > 0);
6527   newCoordinates->setChart(mesh_type::sieve_type::chart_type(_orderNewMesh->verticesNormal().min(), _orderNewMesh->verticesCensored().max()));
6528 
6529   const interval_type::const_iterator newVerticesEnd = _orderNewMesh->verticesCensored().end();
6530   for (interval_type::const_iterator v_iter=_orderNewMesh->verticesNormal().begin(); v_iter != newVerticesEnd; ++v_iter) {
6531     newCoordinates->setFiberDimension(*v_iter, spaceDim);
6532   } // for
6533   newCoordinates->allocatePoint();
6534 
6535   interval_type::const_iterator oldVerticesEnd = _orderOldMesh->verticesNormal().end();
6536   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesNormal().begin(), vNew_iter=_orderNewMesh->verticesNormal().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
6537     //std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl;
6538     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
6539   } // for
6540   oldVerticesEnd = _orderOldMesh->verticesCensored().end();
6541   for (interval_type::const_iterator vOld_iter=_orderOldMesh->verticesCensored().begin(), vNew_iter=_orderNewMesh->verticesCensored().begin(); vOld_iter != oldVerticesEnd; ++vOld_iter, ++vNew_iter) {
6542     //std::cout << "Copy coordinates from old vertex " << *vOld_iter << " to new vertex " << *vNew_iter << std::endl;
6543     newCoordinates->updatePoint(*vNew_iter, coordinates->restrictPoint(*vOld_iter));
6544   } // for
6545 
6546   refiner.setCoordsNewVertices(newCoordinates, coordinates);
6547 
6548   // Create sensored depth
6549   const ALE::Obj<SieveFlexMesh::label_type>& censoredLabel = newMesh->createLabel("censored depth");
6550   assert(!censoredLabel.isNull());
6551 
6552   mesh_type::DepthVisitor depthVisitor(*newSieve, _orderNewMesh->verticesCensored().min(), *censoredLabel);
6553 
6554   newSieve->roots(depthVisitor);
6555   while(depthVisitor.isModified()) {
6556     // FIX: Avoid the copy here somehow by fixing the traversal
6557     std::vector<mesh_type::point_type> modifiedPoints(depthVisitor.getModifiedPoints().begin(), depthVisitor.getModifiedPoints().end());
6558 
6559     depthVisitor.clear();
6560     newSieve->support(modifiedPoints, depthVisitor);
6561   } // while
6562   // Stratify refined mesh
6563   // Calculate new point SF
6564   _calcNewOverlap(newMesh, mesh, refiner);
6565   // Calculate new labels
6566   _createLabels(newMesh, mesh, refiner);
6567 #endif
6568   PetscFunctionReturn(0);
6569 }
6570 
6571 #undef __FUNCT__
6572 #define __FUNCT__ "DMPlexSetRefinementUniform"
6573 PetscErrorCode DMPlexSetRefinementUniform(DM dm, PetscBool refinementUniform)
6574 {
6575   DM_Plex *mesh = (DM_Plex *) dm->data;
6576 
6577   PetscFunctionBegin;
6578   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6579   mesh->refinementUniform = refinementUniform;
6580   PetscFunctionReturn(0);
6581 }
6582 
6583 #undef __FUNCT__
6584 #define __FUNCT__ "DMPlexGetRefinementUniform"
6585 PetscErrorCode DMPlexGetRefinementUniform(DM dm, PetscBool *refinementUniform)
6586 {
6587   DM_Plex *mesh = (DM_Plex *) dm->data;
6588 
6589   PetscFunctionBegin;
6590   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6591   PetscValidPointer(refinementUniform,  2);
6592   *refinementUniform = mesh->refinementUniform;
6593   PetscFunctionReturn(0);
6594 }
6595 
6596 #undef __FUNCT__
6597 #define __FUNCT__ "DMPlexSetRefinementLimit"
6598 PetscErrorCode DMPlexSetRefinementLimit(DM dm, PetscReal refinementLimit)
6599 {
6600   DM_Plex *mesh = (DM_Plex *) dm->data;
6601 
6602   PetscFunctionBegin;
6603   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6604   mesh->refinementLimit = refinementLimit;
6605   PetscFunctionReturn(0);
6606 }
6607 
6608 #undef __FUNCT__
6609 #define __FUNCT__ "DMPlexGetRefinementLimit"
6610 PetscErrorCode DMPlexGetRefinementLimit(DM dm, PetscReal *refinementLimit)
6611 {
6612   DM_Plex *mesh = (DM_Plex *) dm->data;
6613 
6614   PetscFunctionBegin;
6615   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6616   PetscValidPointer(refinementLimit,  2);
6617   /* if (mesh->refinementLimit < 0) = getMaxVolume()/2.0; */
6618   *refinementLimit = mesh->refinementLimit;
6619   PetscFunctionReturn(0);
6620 }
6621 
6622 #undef __FUNCT__
6623 #define __FUNCT__ "DMPlexGetCellRefiner_Private"
6624 PetscErrorCode DMPlexGetCellRefiner_Private(DM dm, CellRefiner *cellRefiner)
6625 {
6626   PetscInt       dim, cStart, coneSize;
6627   PetscErrorCode ierr;
6628 
6629   PetscFunctionBegin;
6630   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6631   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, PETSC_NULL);CHKERRQ(ierr);
6632   ierr = DMPlexGetConeSize(dm, cStart, &coneSize);CHKERRQ(ierr);
6633   switch(dim) {
6634   case 2:
6635     switch(coneSize) {
6636     case 3:
6637       *cellRefiner = 1;break;
6638     case 4:
6639       *cellRefiner = 2;break;
6640     default:
6641       SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown coneSize %d in dimension %d for cell refiner", coneSize, dim);
6642     }
6643     break;
6644   default:
6645     SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Unknown dimension %d for cell refiner", dim);
6646   }
6647   PetscFunctionReturn(0);
6648 }
6649 
6650 #undef __FUNCT__
6651 #define __FUNCT__ "DMRefine_Plex"
6652 PetscErrorCode DMRefine_Plex(DM dm, MPI_Comm comm, DM *dmRefined)
6653 {
6654   PetscReal      refinementLimit;
6655   PetscInt       dim, cStart, cEnd;
6656   char           genname[1024], *name = PETSC_NULL;
6657   PetscBool      isUniform, isTriangle = PETSC_FALSE, isTetgen = PETSC_FALSE, isCTetgen = PETSC_FALSE, flg;
6658   PetscErrorCode ierr;
6659 
6660   PetscFunctionBegin;
6661   ierr = DMPlexGetRefinementUniform(dm, &isUniform);CHKERRQ(ierr);
6662   if (isUniform) {
6663     CellRefiner cellRefiner;
6664 
6665     ierr = DMPlexGetCellRefiner_Private(dm, &cellRefiner);CHKERRQ(ierr);
6666     ierr = DMPlexRefine_Uniform(dm, cellRefiner, dmRefined);CHKERRQ(ierr);
6667     PetscFunctionReturn(0);
6668   }
6669   ierr = DMPlexGetRefinementLimit(dm, &refinementLimit);CHKERRQ(ierr);
6670   if (refinementLimit == 0.0) PetscFunctionReturn(0);
6671   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
6672   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
6673   ierr = PetscOptionsGetString(((PetscObject) dm)->prefix, "-dm_plex_generator", genname, 1024, &flg);CHKERRQ(ierr);
6674   if (flg) {name = genname;}
6675   if (name) {
6676     ierr = PetscStrcmp(name, "triangle", &isTriangle);CHKERRQ(ierr);
6677     ierr = PetscStrcmp(name, "tetgen",   &isTetgen);CHKERRQ(ierr);
6678     ierr = PetscStrcmp(name, "ctetgen",  &isCTetgen);CHKERRQ(ierr);
6679   }
6680   switch(dim) {
6681   case 2:
6682     if (!name || isTriangle) {
6683 #ifdef PETSC_HAVE_TRIANGLE
6684       double  *maxVolumes;
6685       PetscInt c;
6686 
6687       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6688       for (c = 0; c < cEnd-cStart; ++c) {
6689         maxVolumes[c] = refinementLimit;
6690       }
6691       ierr = DMPlexRefine_Triangle(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6692 #else
6693       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement needs external package support.\nPlease reconfigure with --download-triangle.");
6694 #endif
6695     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 2D mesh generation package %s", name);
6696     break;
6697   case 3:
6698     if (!name || isCTetgen) {
6699 #ifdef PETSC_HAVE_CTETGEN
6700       PetscReal *maxVolumes;
6701       PetscInt   c;
6702 
6703       ierr = PetscMalloc((cEnd - cStart) * sizeof(PetscReal), &maxVolumes);CHKERRQ(ierr);
6704       for (c = 0; c < cEnd-cStart; ++c) {
6705         maxVolumes[c] = refinementLimit;
6706       }
6707       ierr = DMPlexRefine_CTetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6708 #else
6709       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "CTetgen needs external package support.\nPlease reconfigure with --download-ctetgen.");
6710 #endif
6711     } else if (isTetgen) {
6712 #ifdef PETSC_HAVE_TETGEN
6713       double  *maxVolumes;
6714       PetscInt c;
6715 
6716       ierr = PetscMalloc((cEnd - cStart) * sizeof(double), &maxVolumes);CHKERRQ(ierr);
6717       for (c = 0; c < cEnd-cStart; ++c) {
6718         maxVolumes[c] = refinementLimit;
6719       }
6720       ierr = DMPlexRefine_Tetgen(dm, maxVolumes, dmRefined);CHKERRQ(ierr);
6721 #else
6722       SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Tetgen needs external package support.\nPlease reconfigure with --with-c-language=cxx --download-tetgen.");
6723 #endif
6724     } else SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unknown 3D mesh generation package %s", name);
6725     break;
6726   default:
6727     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Mesh refinement in dimension %d is not supported.", dim);
6728   }
6729   PetscFunctionReturn(0);
6730 }
6731 
6732 #undef __FUNCT__
6733 #define __FUNCT__ "DMPlexGetDepth"
6734 /*@
6735   DMPlexGetDepth - get the number of strata
6736 
6737   Not Collective
6738 
6739   Input Parameters:
6740 . dm           - The DMPlex object
6741 
6742   Output Parameters:
6743 . depth - number of strata
6744 
6745   Level: developer
6746 
6747   Notes:
6748   DMPlexGetHeightStratum(dm,0,..) should return the same points as DMPlexGetDepthStratum(dm,depth,..).
6749 
6750 .keywords: mesh, points
6751 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepthStratum()
6752 @*/
6753 PetscErrorCode DMPlexGetDepth(DM dm, PetscInt *depth)
6754 {
6755   PetscInt       d;
6756   PetscErrorCode ierr;
6757 
6758   PetscFunctionBegin;
6759   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6760   PetscValidPointer(depth, 2);
6761   ierr = DMPlexGetLabelSize(dm, "depth", &d);CHKERRQ(ierr);
6762   *depth = d-1;
6763   PetscFunctionReturn(0);
6764 }
6765 
6766 #undef __FUNCT__
6767 #define __FUNCT__ "DMPlexGetDepthStratum"
6768 /*@
6769   DMPlexGetDepthStratum - Get the bounds [start, end) for all points at a certain depth.
6770 
6771   Not Collective
6772 
6773   Input Parameters:
6774 + dm           - The DMPlex object
6775 - stratumValue - The requested depth
6776 
6777   Output Parameters:
6778 + start - The first point at this depth
6779 - end   - One beyond the last point at this depth
6780 
6781   Level: developer
6782 
6783 .keywords: mesh, points
6784 .seealso: DMPlexGetHeightStratum(), DMPlexGetDepth()
6785 @*/
6786 PetscErrorCode DMPlexGetDepthStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) {
6787   DM_Plex    *mesh = (DM_Plex *) dm->data;
6788   DMLabel        next = mesh->labels;
6789   PetscBool      flg  = PETSC_FALSE;
6790   PetscInt       depth;
6791   PetscErrorCode ierr;
6792 
6793   PetscFunctionBegin;
6794   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6795   if (stratumValue < 0) {
6796     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6797     PetscFunctionReturn(0);
6798   } else {
6799     PetscInt pStart, pEnd;
6800 
6801     if (start) {*start = 0;}
6802     if (end)   {*end   = 0;}
6803     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6804     if (pStart == pEnd) {PetscFunctionReturn(0);}
6805   }
6806   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6807   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6808   /* We should have a generic GetLabel() and a Label class */
6809   while(next) {
6810     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6811     if (flg) break;
6812     next = next->next;
6813   }
6814   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6815   depth = stratumValue;
6816   if ((depth < 0) || (depth >= next->numStrata)) {
6817     if (start) {*start = 0;}
6818     if (end)   {*end   = 0;}
6819   } else {
6820     if (start) {*start = next->points[next->stratumOffsets[depth]];}
6821     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
6822   }
6823   PetscFunctionReturn(0);
6824 }
6825 
6826 #undef __FUNCT__
6827 #define __FUNCT__ "DMPlexGetHeightStratum"
6828 /*@
6829   DMPlexGetHeightStratum - Get the bounds [start, end) for all points at a certain height.
6830 
6831   Not Collective
6832 
6833   Input Parameters:
6834 + dm           - The DMPlex object
6835 - stratumValue - The requested height
6836 
6837   Output Parameters:
6838 + start - The first point at this height
6839 - end   - One beyond the last point at this height
6840 
6841   Level: developer
6842 
6843 .keywords: mesh, points
6844 .seealso: DMPlexGetDepthStratum(), DMPlexGetDepth()
6845 @*/
6846 PetscErrorCode DMPlexGetHeightStratum(DM dm, PetscInt stratumValue, PetscInt *start, PetscInt *end) {
6847   DM_Plex    *mesh = (DM_Plex *) dm->data;
6848   DMLabel        next = mesh->labels;
6849   PetscBool      flg  = PETSC_FALSE;
6850   PetscInt       depth;
6851   PetscErrorCode ierr;
6852 
6853   PetscFunctionBegin;
6854   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
6855   if (stratumValue < 0) {
6856     ierr = DMPlexGetChart(dm, start, end);CHKERRQ(ierr);
6857   } else {
6858     PetscInt pStart, pEnd;
6859 
6860     if (start) {*start = 0;}
6861     if (end)   {*end   = 0;}
6862     ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6863     if (pStart == pEnd) {PetscFunctionReturn(0);}
6864   }
6865   ierr = DMPlexHasLabel(dm, "depth", &flg);CHKERRQ(ierr);
6866   if (!flg) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "No label named depth was found");CHKERRQ(ierr);
6867   /* We should have a generic GetLabel() and a Label class */
6868   while(next) {
6869     ierr = PetscStrcmp("depth", next->name, &flg);CHKERRQ(ierr);
6870     if (flg) break;
6871     next = next->next;
6872   }
6873   /* Strata are sorted and contiguous -- In addition, depth/height is either full or 1-level */
6874   depth = next->stratumValues[next->numStrata-1] - stratumValue;
6875   if ((depth < 0) || (depth >= next->numStrata)) {
6876     if (start) {*start = 0;}
6877     if (end)   {*end   = 0;}
6878   } else {
6879     if (start) {*start = next->points[next->stratumOffsets[depth]];}
6880     if (end)   {*end   = next->points[next->stratumOffsets[depth]+next->stratumSizes[depth]-1]+1;}
6881   }
6882   PetscFunctionReturn(0);
6883 }
6884 
6885 #undef __FUNCT__
6886 #define __FUNCT__ "DMPlexCreateSectionInitial"
6887 /* Set the number of dof on each point and separate by fields */
6888 PetscErrorCode DMPlexCreateSectionInitial(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscSection *section) {
6889   PetscInt      *numDofTot;
6890   PetscInt       pStart = 0, pEnd = 0;
6891   PetscInt       p, d, f;
6892   PetscErrorCode ierr;
6893 
6894   PetscFunctionBegin;
6895   ierr = PetscMalloc((dim+1) * sizeof(PetscInt), &numDofTot);CHKERRQ(ierr);
6896   for(d = 0; d <= dim; ++d) {
6897     numDofTot[d] = 0;
6898     for(f = 0; f < numFields; ++f) {
6899       numDofTot[d] += numDof[f*(dim+1)+d];
6900     }
6901   }
6902   ierr = PetscSectionCreate(((PetscObject) dm)->comm, section);CHKERRQ(ierr);
6903   if (numFields > 0) {
6904     ierr = PetscSectionSetNumFields(*section, numFields);CHKERRQ(ierr);
6905     if (numComp) {
6906       for(f = 0; f < numFields; ++f) {
6907         ierr = PetscSectionSetFieldComponents(*section, f, numComp[f]);CHKERRQ(ierr);
6908       }
6909     }
6910   }
6911   ierr = DMPlexGetChart(dm, &pStart, &pEnd);CHKERRQ(ierr);
6912   ierr = PetscSectionSetChart(*section, pStart, pEnd);CHKERRQ(ierr);
6913   for(d = 0; d <= dim; ++d) {
6914     ierr = DMPlexGetDepthStratum(dm, d, &pStart, &pEnd);CHKERRQ(ierr);
6915     for(p = pStart; p < pEnd; ++p) {
6916       for(f = 0; f < numFields; ++f) {
6917         ierr = PetscSectionSetFieldDof(*section, p, f, numDof[f*(dim+1)+d]);CHKERRQ(ierr);
6918       }
6919       ierr = PetscSectionSetDof(*section, p, numDofTot[d]);CHKERRQ(ierr);
6920     }
6921   }
6922   ierr = PetscFree(numDofTot);CHKERRQ(ierr);
6923   PetscFunctionReturn(0);
6924 }
6925 
6926 #undef __FUNCT__
6927 #define __FUNCT__ "DMPlexCreateSectionBCDof"
6928 /* Set the number of dof on each point and separate by fields
6929    If constDof is PETSC_DETERMINE, constrain every dof on the point
6930 */
6931 PetscErrorCode DMPlexCreateSectionBCDof(DM dm, PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscInt constDof, PetscSection section) {
6932   PetscInt       numFields;
6933   PetscInt       bc;
6934   PetscErrorCode ierr;
6935 
6936   PetscFunctionBegin;
6937   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6938   for (bc = 0; bc < numBC; ++bc) {
6939     PetscInt        field = 0;
6940     const PetscInt *idx;
6941     PetscInt        n, i;
6942 
6943     if (numFields) {field = bcField[bc];}
6944     ierr = ISGetLocalSize(bcPoints[bc], &n);CHKERRQ(ierr);
6945     ierr = ISGetIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6946     for (i = 0; i < n; ++i) {
6947       const PetscInt p = idx[i];
6948       PetscInt       numConst = constDof;
6949 
6950       /* Constrain every dof on the point */
6951       if (numConst < 0) {
6952         if (numFields) {
6953           ierr = PetscSectionGetFieldDof(section, p, field, &numConst);CHKERRQ(ierr);
6954         } else {
6955           ierr = PetscSectionGetDof(section, p, &numConst);CHKERRQ(ierr);
6956         }
6957       }
6958       if (numFields) {
6959         ierr = PetscSectionAddFieldConstraintDof(section, p, field, numConst);CHKERRQ(ierr);
6960       }
6961       ierr = PetscSectionAddConstraintDof(section, p, numConst);CHKERRQ(ierr);
6962     }
6963     ierr = ISRestoreIndices(bcPoints[bc], &idx);CHKERRQ(ierr);
6964   }
6965   PetscFunctionReturn(0);
6966 }
6967 
6968 #undef __FUNCT__
6969 #define __FUNCT__ "DMPlexCreateSectionBCIndicesAll"
6970 /* Set the constrained indices on each point and separate by fields */
6971 PetscErrorCode DMPlexCreateSectionBCIndicesAll(DM dm, PetscSection section) {
6972   PetscInt      *maxConstraints;
6973   PetscInt       numFields, f, pStart = 0, pEnd = 0, p;
6974   PetscErrorCode ierr;
6975 
6976   PetscFunctionBegin;
6977   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
6978   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
6979   ierr = PetscMalloc((numFields+1) * sizeof(PetscInt), &maxConstraints);CHKERRQ(ierr);
6980   for(f = 0; f <= numFields; ++f) {maxConstraints[f] = 0;}
6981   for(p = pStart; p < pEnd; ++p) {
6982     PetscInt cdof;
6983 
6984     if (numFields) {
6985       for(f = 0; f < numFields; ++f) {
6986         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cdof);CHKERRQ(ierr);
6987         maxConstraints[f] = PetscMax(maxConstraints[f], cdof);
6988       }
6989     } else {
6990       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
6991       maxConstraints[0] = PetscMax(maxConstraints[0], cdof);
6992     }
6993   }
6994   for (f = 0; f < numFields; ++f) {
6995     maxConstraints[numFields] += maxConstraints[f];
6996   }
6997   if (maxConstraints[numFields]) {
6998     PetscInt *indices;
6999 
7000     ierr = PetscMalloc(maxConstraints[numFields] * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7001     for (p = pStart; p < pEnd; ++p) {
7002       PetscInt cdof, d;
7003 
7004       ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7005       if (cdof) {
7006         if (cdof > maxConstraints[numFields]) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_LIB, "Likely memory corruption, point %D cDof %D > maxConstraints %D", p, cdof, maxConstraints[numFields]);
7007         if (numFields) {
7008           PetscInt numConst = 0, foff = 0;
7009 
7010           for (f = 0; f < numFields; ++f) {
7011             PetscInt cfdof, fdof;
7012 
7013             ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7014             ierr = PetscSectionGetFieldConstraintDof(section, p, f, &cfdof);CHKERRQ(ierr);
7015             /* Change constraint numbering from absolute local dof number to field relative local dof number */
7016             for(d = 0; d < cfdof; ++d) {
7017               indices[numConst+d] = d;
7018             }
7019             ierr = PetscSectionSetFieldConstraintIndices(section, p, f, &indices[numConst]);CHKERRQ(ierr);
7020             for(d = 0; d < cfdof; ++d) {
7021               indices[numConst+d] += foff;
7022             }
7023             numConst += cfdof;
7024             foff     += fdof;
7025           }
7026           if (cdof != numConst) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7027         } else {
7028           for (d = 0; d < cdof; ++d) {
7029             indices[d] = d;
7030           }
7031         }
7032         ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7033       }
7034     }
7035     ierr = PetscFree(indices);CHKERRQ(ierr);
7036   }
7037   ierr = PetscFree(maxConstraints);CHKERRQ(ierr);
7038   PetscFunctionReturn(0);
7039 }
7040 
7041 #undef __FUNCT__
7042 #define __FUNCT__ "DMPlexCreateSectionBCIndicesField"
7043 /* Set the constrained field indices on each point */
7044 PetscErrorCode DMPlexCreateSectionBCIndicesField(DM dm, PetscInt field, IS bcPoints, IS constraintIndices, PetscSection section) {
7045   const PetscInt *points, *indices;
7046   PetscInt        numFields, maxDof, numPoints, p, numConstraints;
7047   PetscErrorCode  ierr;
7048 
7049   PetscFunctionBegin;
7050   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7051   if ((field < 0) || (field >= numFields)) SETERRQ3(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Section field %d should be in [%d, %d)", field, 0, numFields);
7052 
7053   ierr = ISGetLocalSize(bcPoints, &numPoints);CHKERRQ(ierr);
7054   ierr = ISGetIndices(bcPoints, &points);CHKERRQ(ierr);
7055   if (!constraintIndices) {
7056     PetscInt *idx, i;
7057 
7058     ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7059     ierr = PetscMalloc(maxDof * sizeof(PetscInt), &idx);CHKERRQ(ierr);
7060     for(i = 0; i < maxDof; ++i) {idx[i] = i;}
7061     for(p = 0; p < numPoints; ++p) {
7062       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, idx);CHKERRQ(ierr);
7063     }
7064     ierr = PetscFree(idx);CHKERRQ(ierr);
7065   } else {
7066     ierr = ISGetLocalSize(constraintIndices, &numConstraints);CHKERRQ(ierr);
7067     ierr = ISGetIndices(constraintIndices, &indices);CHKERRQ(ierr);
7068     for(p = 0; p < numPoints; ++p) {
7069       PetscInt fcdof;
7070 
7071       ierr = PetscSectionGetFieldConstraintDof(section, points[p], field, &fcdof);CHKERRQ(ierr);
7072       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);
7073       ierr = PetscSectionSetFieldConstraintIndices(section, points[p], field, indices);CHKERRQ(ierr);
7074     }
7075     ierr = ISRestoreIndices(constraintIndices, &indices);CHKERRQ(ierr);
7076   }
7077   ierr = ISRestoreIndices(bcPoints, &points);CHKERRQ(ierr);
7078   PetscFunctionReturn(0);
7079 }
7080 
7081 #undef __FUNCT__
7082 #define __FUNCT__ "DMPlexCreateSectionBCIndices"
7083 /* Set the constrained indices on each point and separate by fields */
7084 PetscErrorCode DMPlexCreateSectionBCIndices(DM dm, PetscSection section) {
7085   PetscInt      *indices;
7086   PetscInt       numFields, maxDof, f, pStart = 0, pEnd = 0, p;
7087   PetscErrorCode ierr;
7088 
7089   PetscFunctionBegin;
7090   ierr = PetscSectionGetMaxDof(section, &maxDof);CHKERRQ(ierr);
7091   ierr = PetscMalloc(maxDof * sizeof(PetscInt), &indices);CHKERRQ(ierr);
7092   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7093   if (!numFields) SETERRQ(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "This function only works after users have set field constraint indices.");
7094   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7095   for (p = pStart; p < pEnd; ++p) {
7096     PetscInt cdof, d;
7097 
7098     ierr = PetscSectionGetConstraintDof(section, p, &cdof);CHKERRQ(ierr);
7099     if (cdof) {
7100       PetscInt numConst = 0, foff = 0;
7101 
7102       for (f = 0; f < numFields; ++f) {
7103         const PetscInt *fcind;
7104         PetscInt        fdof, fcdof;
7105 
7106         ierr = PetscSectionGetFieldDof(section, p, f, &fdof);CHKERRQ(ierr);
7107         ierr = PetscSectionGetFieldConstraintDof(section, p, f, &fcdof);CHKERRQ(ierr);
7108         if (fcdof) {ierr = PetscSectionGetFieldConstraintIndices(section, p, f, &fcind);CHKERRQ(ierr);}
7109         /* Change constraint numbering from field relative local dof number to absolute local dof number */
7110         for(d = 0; d < fcdof; ++d) {
7111           indices[numConst+d] = fcind[d]+foff;
7112         }
7113         foff     += fdof;
7114         numConst += fcdof;
7115       }
7116       if (cdof != numConst) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_LIB, "Total number of field constraints %D should be %D", numConst, cdof);
7117       ierr = PetscSectionSetConstraintIndices(section, p, indices);CHKERRQ(ierr);
7118     }
7119   }
7120   ierr = PetscFree(indices);CHKERRQ(ierr);
7121   PetscFunctionReturn(0);
7122 }
7123 
7124 #undef __FUNCT__
7125 #define __FUNCT__ "DMPlexCreateSection"
7126 /*@C
7127   DMPlexCreateSection - Create a PetscSection based upon the dof layout specification provided.
7128 
7129   Not Collective
7130 
7131   Input Parameters:
7132 + dm        - The DMPlex object
7133 . dim       - The spatial dimension of the problem
7134 . numFields - The number of fields in the problem
7135 . numComp   - An array of size numFields that holds the number of components for each field
7136 . numDof    - An array of size numFields*(dim+1) which holds the number of dof for each field on a mesh piece of dimension d
7137 . numBC     - The number of boundary conditions
7138 . bcField   - An array of size numBC giving the field number for each boundry condition
7139 - bcPoints  - An array of size numBC giving an IS holding the sieve points to which each boundary condition applies
7140 
7141   Output Parameter:
7142 . section - The PetscSection object
7143 
7144   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
7145   nubmer of dof for field 0 on each edge.
7146 
7147   Level: developer
7148 
7149 .keywords: mesh, elements
7150 .seealso: DMPlexCreate(), PetscSectionCreate()
7151 @*/
7152 PetscErrorCode DMPlexCreateSection(DM dm, PetscInt dim, PetscInt numFields,const PetscInt numComp[],const PetscInt numDof[], PetscInt numBC,const PetscInt bcField[],const IS bcPoints[], PetscSection *section) {
7153   PetscErrorCode ierr;
7154 
7155   PetscFunctionBegin;
7156   ierr = DMPlexCreateSectionInitial(dm, dim, numFields, numComp, numDof, section);CHKERRQ(ierr);
7157   ierr = DMPlexCreateSectionBCDof(dm, numBC, bcField, bcPoints, PETSC_DETERMINE, *section);CHKERRQ(ierr);
7158   ierr = PetscSectionSetUp(*section);CHKERRQ(ierr);
7159   if (numBC) {ierr = DMPlexCreateSectionBCIndicesAll(dm, *section);CHKERRQ(ierr);}
7160   {
7161     PetscBool view = PETSC_FALSE;
7162 
7163     ierr = PetscOptionsHasName(((PetscObject) dm)->prefix, "-section_view", &view);CHKERRQ(ierr);
7164     if (view) {ierr = PetscSectionView(*section, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);}
7165   }
7166   PetscFunctionReturn(0);
7167 }
7168 
7169 #undef __FUNCT__
7170 #define __FUNCT__ "DMCreateCoordinateDM_Plex"
7171 PetscErrorCode DMCreateCoordinateDM_Plex(DM dm, DM *cdm) {
7172   PetscSection   section;
7173   PetscErrorCode ierr;
7174 
7175   PetscFunctionBegin;
7176   ierr = DMPlexClone(dm, cdm);CHKERRQ(ierr);
7177   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
7178   ierr = DMSetDefaultSection(*cdm, section);CHKERRQ(ierr);
7179   PetscFunctionReturn(0);
7180 }
7181 
7182 #undef __FUNCT__
7183 #define __FUNCT__ "DMPlexGetCoordinateSection"
7184 /*@
7185   DMPlexGetCoordinateSection - Retrieve the layout of coordinate values over the mesh.
7186 
7187   Not Collective
7188 
7189   Input Parameter:
7190 . dm - The DMPlex object
7191 
7192   Output Parameter:
7193 . section - The PetscSection object
7194 
7195   Level: intermediate
7196 
7197 .keywords: mesh, coordinates
7198 .seealso: DMGetCoordinateDM(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7199 @*/
7200 PetscErrorCode DMPlexGetCoordinateSection(DM dm, PetscSection *section) {
7201   DM cdm;
7202   PetscErrorCode ierr;
7203 
7204   PetscFunctionBegin;
7205   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7206   PetscValidPointer(section, 2);
7207   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7208   ierr = DMGetDefaultSection(cdm, section);CHKERRQ(ierr);
7209   PetscFunctionReturn(0);
7210 }
7211 
7212 #undef __FUNCT__
7213 #define __FUNCT__ "DMPlexSetCoordinateSection"
7214 /*@
7215   DMPlexSetCoordinateSection - Set the layout of coordinate values over the mesh.
7216 
7217   Not Collective
7218 
7219   Input Parameters:
7220 + dm      - The DMPlex object
7221 - section - The PetscSection object
7222 
7223   Level: intermediate
7224 
7225 .keywords: mesh, coordinates
7226 .seealso: DMPlexGetCoordinateSection(), DMPlexGetDefaultSection(), DMPlexSetDefaultSection()
7227 @*/
7228 PetscErrorCode DMPlexSetCoordinateSection(DM dm, PetscSection section) {
7229   DM             cdm;
7230   PetscErrorCode ierr;
7231 
7232   PetscFunctionBegin;
7233   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7234   ierr = DMGetCoordinateDM(dm, &cdm);CHKERRQ(ierr);
7235   ierr = DMSetDefaultSection(cdm, section);CHKERRQ(ierr);
7236   PetscFunctionReturn(0);
7237 }
7238 
7239 #undef __FUNCT__
7240 #define __FUNCT__ "DMPlexGetConeSection"
7241 PetscErrorCode DMPlexGetConeSection(DM dm, PetscSection *section) {
7242   DM_Plex *mesh = (DM_Plex *) dm->data;
7243 
7244   PetscFunctionBegin;
7245   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7246   if (section) *section = mesh->coneSection;
7247   PetscFunctionReturn(0);
7248 }
7249 
7250 #undef __FUNCT__
7251 #define __FUNCT__ "DMPlexGetCones"
7252 PetscErrorCode DMPlexGetCones(DM dm, PetscInt *cones[]) {
7253   DM_Plex *mesh = (DM_Plex *) dm->data;
7254 
7255   PetscFunctionBegin;
7256   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7257   if (cones) *cones = mesh->cones;
7258   PetscFunctionReturn(0);
7259 }
7260 
7261 #undef __FUNCT__
7262 #define __FUNCT__ "DMPlexGetConeOrientations"
7263 PetscErrorCode DMPlexGetConeOrientations(DM dm, PetscInt *coneOrientations[]) {
7264   DM_Plex *mesh = (DM_Plex *) dm->data;
7265 
7266   PetscFunctionBegin;
7267   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7268   if (coneOrientations) *coneOrientations = mesh->coneOrientations;
7269   PetscFunctionReturn(0);
7270 }
7271 
7272 #undef __FUNCT__
7273 #define __FUNCT__ "DMPlexLocatePoint_Simplex_2D"
7274 PetscErrorCode DMPlexLocatePoint_Simplex_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7275 {
7276   const PetscInt embedDim = 2;
7277   PetscReal      x = PetscRealPart(point[0]);
7278   PetscReal      y = PetscRealPart(point[1]);
7279   PetscReal      v0[2], J[4], invJ[4], detJ;
7280   PetscReal      xi, eta;
7281   PetscErrorCode ierr;
7282 
7283   PetscFunctionBegin;
7284   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7285   xi  = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]);
7286   eta = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]);
7287 
7288   if ((xi >= 0.0) && (eta >= 0.0) && (xi + eta <= 2.0)) {
7289     *cell = c;
7290   } else {
7291     *cell = -1;
7292   }
7293   PetscFunctionReturn(0);
7294 }
7295 
7296 #undef __FUNCT__
7297 #define __FUNCT__ "DMPlexLocatePoint_General_2D"
7298 PetscErrorCode DMPlexLocatePoint_General_2D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7299 {
7300   PetscSection       coordSection;
7301   Vec                coordsLocal;
7302   const PetscScalar *coords;
7303   const PetscInt     faces[8]  = {0, 1, 1, 2, 2, 3, 3, 0};
7304   PetscReal          x         = PetscRealPart(point[0]);
7305   PetscReal          y         = PetscRealPart(point[1]);
7306   PetscInt           crossings = 0, f;
7307   PetscErrorCode     ierr;
7308 
7309   PetscFunctionBegin;
7310   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7311   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7312   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7313   for(f = 0; f < 4; ++f) {
7314     PetscReal x_i   = PetscRealPart(coords[faces[2*f+0]*2+0]);
7315     PetscReal y_i   = PetscRealPart(coords[faces[2*f+0]*2+1]);
7316     PetscReal x_j   = PetscRealPart(coords[faces[2*f+1]*2+0]);
7317     PetscReal y_j   = PetscRealPart(coords[faces[2*f+1]*2+1]);
7318     PetscReal slope = (y_j - y_i) / (x_j - x_i);
7319     PetscBool cond1 = (x_i <= x) && (x < x_j) ? PETSC_TRUE : PETSC_FALSE;
7320     PetscBool cond2 = (x_j <= x) && (x < x_i) ? PETSC_TRUE : PETSC_FALSE;
7321     PetscBool above = (y < slope * (x - x_i) + y_i) ? PETSC_TRUE : PETSC_FALSE;
7322     if ((cond1 || cond2)  && above) ++crossings;
7323   }
7324   if (crossings % 2) {
7325     *cell = c;
7326   } else {
7327     *cell = -1;
7328   }
7329   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7330   PetscFunctionReturn(0);
7331 }
7332 
7333 #undef __FUNCT__
7334 #define __FUNCT__ "DMPlexLocatePoint_Simplex_3D"
7335 PetscErrorCode DMPlexLocatePoint_Simplex_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7336 {
7337   const PetscInt embedDim = 3;
7338   PetscReal      v0[3], J[9], invJ[9], detJ;
7339   PetscReal      x = PetscRealPart(point[0]);
7340   PetscReal      y = PetscRealPart(point[1]);
7341   PetscReal      z = PetscRealPart(point[2]);
7342   PetscReal      xi, eta, zeta;
7343   PetscErrorCode ierr;
7344 
7345   PetscFunctionBegin;
7346   ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
7347   xi   = invJ[0*embedDim+0]*(x - v0[0]) + invJ[0*embedDim+1]*(y - v0[1]) + invJ[0*embedDim+2]*(z - v0[2]);
7348   eta  = invJ[1*embedDim+0]*(x - v0[0]) + invJ[1*embedDim+1]*(y - v0[1]) + invJ[1*embedDim+2]*(z - v0[2]);
7349   zeta = invJ[2*embedDim+0]*(x - v0[0]) + invJ[2*embedDim+1]*(y - v0[1]) + invJ[2*embedDim+2]*(z - v0[2]);
7350 
7351   if ((xi >= 0.0) && (eta >= 0.0) && (zeta >= 0.0) && (xi + eta + zeta <= 2.0)) {
7352     *cell = c;
7353   } else {
7354     *cell = -1;
7355   }
7356   PetscFunctionReturn(0);
7357 }
7358 
7359 #undef __FUNCT__
7360 #define __FUNCT__ "DMPlexLocatePoint_General_3D"
7361 PetscErrorCode DMPlexLocatePoint_General_3D(DM dm, const PetscScalar point[], PetscInt c, PetscInt *cell)
7362 {
7363   PetscSection       coordSection;
7364   Vec                coordsLocal;
7365   const PetscScalar *coords;
7366   const PetscInt     faces[24] = {0, 1, 2, 3,  5, 4, 7, 6,  1, 0, 4, 5,
7367                                   3, 2, 6, 7,  1, 5, 6, 2,  0, 3, 7, 4};
7368   PetscBool          found     = PETSC_TRUE;
7369   PetscInt           f;
7370   PetscErrorCode     ierr;
7371 
7372   PetscFunctionBegin;
7373   ierr = DMGetCoordinatesLocal(dm, &coordsLocal);CHKERRQ(ierr);
7374   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
7375   ierr = DMPlexVecGetClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7376   for(f = 0; f < 6; ++f) {
7377     /* Check the point is under plane */
7378     /*   Get face normal */
7379     PetscReal v_i[3]    = {PetscRealPart(coords[faces[f*4+3]*3+0]-coords[faces[f*4+0]*3+0]),
7380                            PetscRealPart(coords[faces[f*4+3]*3+1]-coords[faces[f*4+0]*3+1]),
7381                            PetscRealPart(coords[faces[f*4+3]*3+2]-coords[faces[f*4+0]*3+2])};
7382     PetscReal v_j[3]    = {PetscRealPart(coords[faces[f*4+1]*3+0]-coords[faces[f*4+0]*3+0]),
7383                            PetscRealPart(coords[faces[f*4+1]*3+1]-coords[faces[f*4+0]*3+1]),
7384                            PetscRealPart(coords[faces[f*4+1]*3+2]-coords[faces[f*4+0]*3+2])};
7385     PetscReal normal[3] = {v_i[1]*v_j[2] - v_i[2]*v_j[1], v_i[2]*v_j[0] - v_i[0]*v_j[2], v_i[0]*v_j[1] - v_i[1]*v_j[0]};
7386     PetscReal pp[3]     = {PetscRealPart(coords[faces[f*4+0]*3+0] - point[0]),
7387                            PetscRealPart(coords[faces[f*4+0]*3+1] - point[1]),
7388                            PetscRealPart(coords[faces[f*4+0]*3+2] - point[2])};
7389     PetscReal dot       = normal[0]*pp[0] + normal[1]*pp[1] + normal[2]*pp[2];
7390     /* Check that projected point is in face (2D location problem) */
7391     if (dot < 0.0) {
7392       found = PETSC_FALSE;
7393       break;
7394     }
7395   }
7396   if (found) {
7397     *cell = c;
7398   } else {
7399     *cell = -1;
7400   }
7401   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordsLocal, c, PETSC_NULL, &coords);CHKERRQ(ierr);
7402   PetscFunctionReturn(0);
7403 }
7404 
7405 #undef __FUNCT__
7406 #define __FUNCT__ "DMLocatePoints_Plex"
7407 /*
7408  Need to implement using the guess
7409 */
7410 PetscErrorCode DMLocatePoints_Plex(DM dm, Vec v, IS *cellIS)
7411 {
7412   PetscInt       cell = -1/*, guess = -1*/;
7413   PetscInt       bs, numPoints, p;
7414   PetscInt       dim, cStart, cEnd, cMax, c, coneSize;
7415   PetscInt      *cells;
7416   PetscScalar   *a;
7417   PetscErrorCode ierr;
7418 
7419   PetscFunctionBegin;
7420   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
7421   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
7422   ierr = DMPlexGetVTKBounds(dm, &cMax, PETSC_NULL);CHKERRQ(ierr);
7423   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
7424   ierr = VecGetLocalSize(v, &numPoints);CHKERRQ(ierr);
7425   ierr = VecGetBlockSize(v, &bs);CHKERRQ(ierr);
7426   ierr = VecGetArray(v, &a);CHKERRQ(ierr);
7427   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);
7428   numPoints /= bs;
7429   ierr = PetscMalloc(numPoints * sizeof(PetscInt), &cells);CHKERRQ(ierr);
7430   for(p = 0; p < numPoints; ++p) {
7431     const PetscScalar *point = &a[p*bs];
7432 
7433     switch(dim) {
7434     case 2:
7435       for(c = cStart; c < cEnd; ++c) {
7436         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7437         switch(coneSize) {
7438         case 3:
7439           ierr = DMPlexLocatePoint_Simplex_2D(dm, point, c, &cell);CHKERRQ(ierr);
7440           break;
7441         case 4:
7442           ierr = DMPlexLocatePoint_General_2D(dm, point, c, &cell);CHKERRQ(ierr);
7443           break;
7444         default:
7445           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7446         }
7447         if (cell >= 0) break;
7448       }
7449       break;
7450     case 3:
7451       for(c = cStart; c < cEnd; ++c) {
7452         ierr = DMPlexGetConeSize(dm, c, &coneSize);CHKERRQ(ierr);
7453         switch(coneSize) {
7454         case 4:
7455           ierr = DMPlexLocatePoint_Simplex_3D(dm, point, c, &cell);CHKERRQ(ierr);
7456           break;
7457         case 8:
7458           ierr = DMPlexLocatePoint_General_3D(dm, point, c, &cell);CHKERRQ(ierr);
7459           break;
7460         default:
7461           SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for cell with cone size %d", coneSize);
7462         }
7463         if (cell >= 0) break;
7464       }
7465       break;
7466     default:
7467       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "No point location for mesh dimension %d", dim);
7468     }
7469     cells[p] = cell;
7470   }
7471   ierr = VecRestoreArray(v, &a);CHKERRQ(ierr);
7472   ierr = ISCreateGeneral(PETSC_COMM_SELF, numPoints, cells, PETSC_OWN_POINTER, cellIS);CHKERRQ(ierr);
7473   PetscFunctionReturn(0);
7474 }
7475 
7476 /******************************** FEM Support **********************************/
7477 
7478 #undef __FUNCT__
7479 #define __FUNCT__ "DMPlexVecGetClosure"
7480 /*@C
7481   DMPlexVecGetClosure - Get an array of the values on the closure of 'point'
7482 
7483   Not collective
7484 
7485   Input Parameters:
7486 + dm - The DM
7487 . section - The section describing the layout in v, or PETSC_NULL to use the default section
7488 . v - The local vector
7489 - point - The sieve point in the DM
7490 
7491   Output Parameters:
7492 + csize - The number of values in the closure, or PETSC_NULL
7493 - values - The array of values, which is a borrowed array and should not be freed
7494 
7495   Level: intermediate
7496 
7497 .seealso DMPlexVecRestoreClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7498 @*/
7499 PetscErrorCode DMPlexVecGetClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
7500   PetscScalar    *array, *vArray;
7501   PetscInt       *points = PETSC_NULL;
7502   PetscInt        offsets[32];
7503   PetscInt        numFields, size, numPoints, pStart, pEnd, p, q, f;
7504   PetscErrorCode  ierr;
7505 
7506   PetscFunctionBegin;
7507   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7508   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7509   if (!section) {
7510     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7511   }
7512   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7513   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7514   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7515   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7516   /* Compress out points not in the section */
7517   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7518   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7519     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7520       points[q*2]   = points[p];
7521       points[q*2+1] = points[p+1];
7522       ++q;
7523     }
7524   }
7525   numPoints = q;
7526   for (p = 0, size = 0; p < numPoints*2; p += 2) {
7527     PetscInt dof, fdof;
7528 
7529     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7530     for (f = 0; f < numFields; ++f) {
7531       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7532       offsets[f+1] += fdof;
7533     }
7534     size += dof;
7535   }
7536   for (f = 1; f < numFields; ++f) {
7537     offsets[f+1] += offsets[f];
7538   }
7539   if (numFields && offsets[numFields] != size) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], size);
7540   ierr = DMGetWorkArray(dm, size, PETSC_SCALAR, &array);CHKERRQ(ierr);
7541   ierr = VecGetArray(v, &vArray);CHKERRQ(ierr);
7542   for (p = 0; p < numPoints*2; p += 2) {
7543     PetscInt     o = points[p+1];
7544     PetscInt     dof, off, d;
7545     PetscScalar *varr;
7546 
7547     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7548     ierr = PetscSectionGetOffset(section, points[p], &off);CHKERRQ(ierr);
7549     varr = &vArray[off];
7550     if (numFields) {
7551       PetscInt fdof, foff, fcomp, f, c;
7552 
7553       for (f = 0, foff = 0; f < numFields; ++f) {
7554         ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7555         if (o >= 0) {
7556           for (d = 0; d < fdof; ++d, ++offsets[f]) {
7557             array[offsets[f]] = varr[foff+d];
7558           }
7559         } else {
7560           ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7561           for (d = fdof/fcomp-1; d >= 0; --d) {
7562             for (c = 0; c < fcomp; ++c, ++offsets[f]) {
7563               array[offsets[f]] = varr[foff+d*fcomp+c];
7564             }
7565           }
7566         }
7567         foff += fdof;
7568       }
7569     } else {
7570       if (o >= 0) {
7571         for (d = 0; d < dof; ++d, ++offsets[0]) {
7572           array[offsets[0]] = varr[d];
7573         }
7574       } else {
7575         for (d = dof-1; d >= 0; --d, ++offsets[0]) {
7576           array[offsets[0]] = varr[d];
7577         }
7578       }
7579     }
7580   }
7581   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7582   ierr = VecRestoreArray(v, &vArray);CHKERRQ(ierr);
7583   if (csize) *csize = size;
7584   *values = array;
7585   PetscFunctionReturn(0);
7586 }
7587 
7588 #undef __FUNCT__
7589 #define __FUNCT__ "DMPlexVecRestoreClosure"
7590 /*@C
7591   DMPlexVecRestoreClosure - Restore the array of the values on the closure of 'point'
7592 
7593   Not collective
7594 
7595   Input Parameters:
7596 + dm - The DM
7597 . section - The section describing the layout in v, or PETSC_NULL to use the default section
7598 . v - The local vector
7599 . point - The sieve point in the DM
7600 . csize - The number of values in the closure, or PETSC_NULL
7601 - values - The array of values, which is a borrowed array and should not be freed
7602 
7603   Level: intermediate
7604 
7605 .seealso DMPlexVecGetClosure(), DMPlexVecSetClosure(), DMPlexMatSetClosure()
7606 @*/
7607 PetscErrorCode DMPlexVecRestoreClosure(DM dm, PetscSection section, Vec v, PetscInt point, PetscInt *csize, const PetscScalar *values[]) {
7608   PetscInt        size = 0;
7609   PetscErrorCode  ierr;
7610 
7611   PetscFunctionBegin;
7612   /* Should work without recalculating size */
7613   ierr = DMRestoreWorkArray(dm, size, PETSC_SCALAR, (void *) values);CHKERRQ(ierr);
7614   PetscFunctionReturn(0);
7615 }
7616 
7617 PETSC_STATIC_INLINE void add   (PetscScalar *x, PetscScalar y) {*x += y;}
7618 PETSC_STATIC_INLINE void insert(PetscScalar *x, PetscScalar y) {*x  = y;}
7619 
7620 #undef __FUNCT__
7621 #define __FUNCT__ "updatePoint_private"
7622 PetscErrorCode updatePoint_private(PetscSection section, PetscInt point, PetscInt dof, void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[])
7623 {
7624   PetscInt        cdof;  /* The number of constraints on this point */
7625   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7626   PetscScalar    *a;
7627   PetscInt        off, cind = 0, k;
7628   PetscErrorCode  ierr;
7629 
7630   PetscFunctionBegin;
7631   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7632   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7633   a    = &array[off];
7634   if (!cdof || setBC) {
7635     if (orientation >= 0) {
7636       for (k = 0; k < dof; ++k) {
7637         fuse(&a[k], values[k]);
7638       }
7639     } else {
7640       for (k = 0; k < dof; ++k) {
7641         fuse(&a[k], values[dof-k-1]);
7642       }
7643     }
7644   } else {
7645     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7646     if (orientation >= 0) {
7647       for (k = 0; k < dof; ++k) {
7648         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7649         fuse(&a[k], values[k]);
7650       }
7651     } else {
7652       for (k = 0; k < dof; ++k) {
7653         if ((cind < cdof) && (k == cdofs[cind])) {++cind; continue;}
7654         fuse(&a[k], values[dof-k-1]);
7655       }
7656     }
7657   }
7658   PetscFunctionReturn(0);
7659 }
7660 
7661 #undef __FUNCT__
7662 #define __FUNCT__ "updatePointFields_private"
7663 PetscErrorCode updatePointFields_private(PetscSection section, PetscInt point, PetscInt foffs[], void (*fuse)(PetscScalar *, PetscScalar), PetscBool setBC, PetscInt orientation, const PetscScalar values[], PetscScalar array[]) {
7664   PetscScalar   *a;
7665   PetscInt       numFields, off, foff, f;
7666   PetscErrorCode ierr;
7667 
7668   PetscFunctionBegin;
7669   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7670   ierr = PetscSectionGetOffset(section, point, &off);CHKERRQ(ierr);
7671   a    = &array[off];
7672   for (f = 0, foff = 0; f < numFields; ++f) {
7673     PetscInt        fdof, fcomp, fcdof;
7674     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7675     PetscInt        cind = 0, k, c;
7676 
7677     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7678     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7679     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &fcdof);CHKERRQ(ierr);
7680     if (!fcdof || setBC) {
7681       if (orientation >= 0) {
7682         for (k = 0; k < fdof; ++k) {
7683           fuse(&a[foff+k], values[foffs[f]+k]);
7684         }
7685       } else {
7686         for (k = fdof/fcomp-1; k >= 0; --k) {
7687           for (c = 0; c < fcomp; ++c) {
7688             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7689           }
7690         }
7691       }
7692     } else {
7693       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7694       if (orientation >= 0) {
7695         for (k = 0; k < fdof; ++k) {
7696           if ((cind < fcdof) && (k == fcdofs[cind])) {++cind; continue;}
7697           fuse(&a[foff+k], values[foffs[f]+k]);
7698         }
7699       } else {
7700         for (k = fdof/fcomp-1; k >= 0; --k) {
7701           for (c = 0; c < fcomp; ++c) {
7702             if ((cind < fcdof) && (k*fcomp+c == fcdofs[cind])) {++cind; continue;}
7703             fuse(&a[foff+(fdof/fcomp-1-k)*fcomp+c], values[foffs[f]+k*fcomp+c]);
7704           }
7705         }
7706       }
7707     }
7708     foff     += fdof;
7709     foffs[f] += fdof;
7710   }
7711   PetscFunctionReturn(0);
7712 }
7713 
7714 #undef __FUNCT__
7715 #define __FUNCT__ "DMPlexVecSetClosure"
7716 /*@C
7717   DMPlexVecSetClosure - Set an array of the values on the closure of 'point'
7718 
7719   Not collective
7720 
7721   Input Parameters:
7722 + dm - The DM
7723 . section - The section describing the layout in v, or PETSC_NULL to use the default sectionw
7724 . v - The local vector
7725 . point - The sieve point in the DM
7726 . values - The array of values, which is a borrowed array and should not be freed
7727 - mode - The insert mode, where INSERT_ALL_VALUES and ADD_ALL_VALUES also overwrite boundary conditions
7728 
7729   Level: intermediate
7730 
7731 .seealso DMPlexVecGetClosure(), DMPlexMatSetClosure()
7732 @*/
7733 PetscErrorCode DMPlexVecSetClosure(DM dm, PetscSection section, Vec v, PetscInt point, const PetscScalar values[], InsertMode mode) {
7734   PetscScalar    *array;
7735   PetscInt       *points = PETSC_NULL;
7736   PetscInt        offsets[32];
7737   PetscInt        numFields, numPoints, off, dof, pStart, pEnd, p, q, f;
7738   PetscErrorCode  ierr;
7739 
7740   PetscFunctionBegin;
7741   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7742   PetscValidHeaderSpecific(v, VEC_CLASSID, 3);
7743   if (!section) {
7744     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7745   }
7746   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7747   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7748   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7749   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7750   /* Compress out points not in the section */
7751   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
7752   for (p = 0, q = 0; p < numPoints*2; p += 2) {
7753     if ((points[p] >= pStart) && (points[p] < pEnd)) {
7754       points[q*2]   = points[p];
7755       points[q*2+1] = points[p+1];
7756       ++q;
7757     }
7758   }
7759   numPoints = q;
7760   for (p = 0; p < numPoints*2; p += 2) {
7761     PetscInt fdof;
7762 
7763     for (f = 0; f < numFields; ++f) {
7764       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
7765       offsets[f+1] += fdof;
7766     }
7767   }
7768   for (f = 1; f < numFields; ++f) {
7769     offsets[f+1] += offsets[f];
7770   }
7771   ierr = VecGetArray(v, &array);CHKERRQ(ierr);
7772   if (numFields) {
7773     switch(mode) {
7774     case INSERT_VALUES:
7775       for (p = 0; p < numPoints*2; p += 2) {
7776         PetscInt o = points[p+1];
7777         updatePointFields_private(section, points[p], offsets, insert, PETSC_FALSE, o, values, array);
7778       } break;
7779     case INSERT_ALL_VALUES:
7780       for (p = 0; p < numPoints*2; p += 2) {
7781         PetscInt o = points[p+1];
7782         updatePointFields_private(section, points[p], offsets, insert, PETSC_TRUE,  o, values, array);
7783       } break;
7784     case ADD_VALUES:
7785       for (p = 0; p < numPoints*2; p += 2) {
7786         PetscInt o = points[p+1];
7787         updatePointFields_private(section, points[p], offsets, add,    PETSC_FALSE, o, values, array);
7788       } break;
7789     case ADD_ALL_VALUES:
7790       for (p = 0; p < numPoints*2; p += 2) {
7791         PetscInt o = points[p+1];
7792         updatePointFields_private(section, points[p], offsets, add,    PETSC_TRUE,  o, values, array);
7793       } break;
7794     default:
7795       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7796     }
7797   } else {
7798     switch(mode) {
7799     case INSERT_VALUES:
7800       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7801         PetscInt o = points[p+1];
7802         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7803         updatePoint_private(section, points[p], dof, insert, PETSC_FALSE, o, &values[off], array);
7804       } break;
7805     case INSERT_ALL_VALUES:
7806       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7807         PetscInt o = points[p+1];
7808         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7809         updatePoint_private(section, points[p], dof, insert, PETSC_TRUE,  o, &values[off], array);
7810       } break;
7811     case ADD_VALUES:
7812       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7813         PetscInt o = points[p+1];
7814         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7815         updatePoint_private(section, points[p], dof, add,    PETSC_FALSE, o, &values[off], array);
7816       } break;
7817     case ADD_ALL_VALUES:
7818       for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
7819         PetscInt o = points[p+1];
7820         ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
7821         updatePoint_private(section, points[p], dof, add,    PETSC_TRUE,  o, &values[off], array);
7822       } break;
7823     default:
7824       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid insert mode %D", mode);
7825     }
7826   }
7827   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7828   ierr = VecRestoreArray(v, &array);CHKERRQ(ierr);
7829   PetscFunctionReturn(0);
7830 }
7831 
7832 #undef __FUNCT__
7833 #define __FUNCT__ "DMPlexPrintMatSetValues"
7834 PetscErrorCode DMPlexPrintMatSetValues(PetscViewer viewer, Mat A, PetscInt point, PetscInt numIndices, const PetscInt indices[], PetscScalar values[])
7835 {
7836   PetscMPIInt    rank;
7837   PetscInt       i, j;
7838   PetscErrorCode ierr;
7839 
7840   PetscFunctionBegin;
7841   ierr = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr);
7842   ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat for sieve point %D\n", rank, point);CHKERRQ(ierr);
7843   for (i = 0; i < numIndices; i++) {
7844     ierr = PetscViewerASCIIPrintf(viewer, "[%D]mat indices[%D] = %D\n", rank, i, indices[i]);CHKERRQ(ierr);
7845   }
7846   for (i = 0; i < numIndices; i++) {
7847     ierr = PetscViewerASCIIPrintf(viewer, "[%D]", rank);CHKERRQ(ierr);
7848     for (j = 0; j < numIndices; j++) {
7849 #ifdef PETSC_USE_COMPLEX
7850       ierr = PetscViewerASCIIPrintf(viewer, " (%G,%G)", PetscRealPart(values[i*numIndices+j]), PetscImaginaryPart(values[i*numIndices+j]));CHKERRQ(ierr);
7851 #else
7852       ierr = PetscViewerASCIIPrintf(viewer, " %G", values[i*numIndices+j]);CHKERRQ(ierr);
7853 #endif
7854     }
7855     ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr);
7856   }
7857   PetscFunctionReturn(0);
7858 }
7859 
7860 #undef __FUNCT__
7861 #define __FUNCT__ "indicesPoint_private"
7862 /* . off - The global offset of this point */
7863 PetscErrorCode indicesPoint_private(PetscSection section, PetscInt point, PetscInt dof, PetscInt off, PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
7864   PetscInt        cdof;  /* The number of constraints on this point */
7865   const PetscInt *cdofs; /* The indices of the constrained dofs on this point */
7866   PetscInt        cind = 0, k;
7867   PetscErrorCode  ierr;
7868 
7869   PetscFunctionBegin;
7870   ierr = PetscSectionGetDof(section, point, &dof);CHKERRQ(ierr);
7871   ierr = PetscSectionGetConstraintDof(section, point, &cdof);CHKERRQ(ierr);
7872   if (!cdof || setBC) {
7873     if (orientation >= 0) {
7874       for (k = 0; k < dof; ++k) {
7875         indices[k] = off+k;
7876       }
7877     } else {
7878       for (k = 0; k < dof; ++k) {
7879         indices[dof-k-1] = off+k;
7880       }
7881     }
7882   } else {
7883     ierr = PetscSectionGetConstraintIndices(section, point, &cdofs);CHKERRQ(ierr);
7884     if (orientation >= 0) {
7885       for (k = 0; k < dof; ++k) {
7886         if ((cind < cdof) && (k == cdofs[cind])) {
7887           /* Insert check for returning constrained indices */
7888           indices[k] = -(off+k+1);
7889           ++cind;
7890         } else {
7891           indices[k] = off+k-cind;
7892         }
7893       }
7894     } else {
7895       for (k = 0; k < dof; ++k) {
7896         if ((cind < cdof) && (k == cdofs[cind])) {
7897           /* Insert check for returning constrained indices */
7898           indices[dof-k-1] = -(off+k+1);
7899           ++cind;
7900         } else {
7901           indices[dof-k-1] = off+k-cind;
7902         }
7903       }
7904     }
7905   }
7906   PetscFunctionReturn(0);
7907 }
7908 
7909 #undef __FUNCT__
7910 #define __FUNCT__ "indicesPointFields_private"
7911 /* . off - The global offset of this point */
7912 PetscErrorCode indicesPointFields_private(PetscSection section, PetscInt point, PetscInt off, PetscInt foffs[], PetscBool setBC, PetscInt orientation, PetscInt indices[]) {
7913   PetscInt       numFields, foff, f;
7914   PetscErrorCode ierr;
7915 
7916   PetscFunctionBegin;
7917   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7918   for (f = 0, foff = 0; f < numFields; ++f) {
7919     PetscInt        fdof, fcomp, cfdof;
7920     const PetscInt *fcdofs; /* The indices of the constrained dofs for field f on this point */
7921     PetscInt        cind = 0, k, c;
7922 
7923     ierr = PetscSectionGetFieldComponents(section, f, &fcomp);CHKERRQ(ierr);
7924     ierr = PetscSectionGetFieldDof(section, point, f, &fdof);CHKERRQ(ierr);
7925     ierr = PetscSectionGetFieldConstraintDof(section, point, f, &cfdof);CHKERRQ(ierr);
7926     if (!cfdof || setBC) {
7927       if (orientation >= 0) {
7928         for (k = 0; k < fdof; ++k) {
7929           indices[foffs[f]+k] = off+foff+k;
7930         }
7931       } else {
7932         for (k = fdof/fcomp-1; k >= 0; --k) {
7933           for (c = 0; c < fcomp; ++c) {
7934             indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c;
7935           }
7936         }
7937       }
7938     } else {
7939       ierr = PetscSectionGetFieldConstraintIndices(section, point, f, &fcdofs);CHKERRQ(ierr);
7940       if (orientation >= 0) {
7941         for (k = 0; k < fdof; ++k) {
7942           if ((cind < cfdof) && (k == fcdofs[cind])) {
7943             indices[foffs[f]+k] = -(off+foff+k+1);
7944             ++cind;
7945           } else {
7946             indices[foffs[f]+k] = off+foff+k-cind;
7947           }
7948         }
7949       } else {
7950         for (k = fdof/fcomp-1; k >= 0; --k) {
7951           for (c = 0; c < fcomp; ++c) {
7952             if ((cind < cfdof) && ((fdof/fcomp-1-k)*fcomp+c == fcdofs[cind])) {
7953               indices[foffs[f]+k*fcomp+c] = -(off+foff+(fdof/fcomp-1-k)*fcomp+c+1);
7954               ++cind;
7955             } else {
7956               indices[foffs[f]+k*fcomp+c] = off+foff+(fdof/fcomp-1-k)*fcomp+c-cind;
7957             }
7958           }
7959         }
7960       }
7961     }
7962     foff     += fdof - cfdof;
7963     foffs[f] += fdof;
7964   }
7965   PetscFunctionReturn(0);
7966 }
7967 
7968 #undef __FUNCT__
7969 #define __FUNCT__ "DMPlexMatSetClosure"
7970 PetscErrorCode DMPlexMatSetClosure(DM dm, PetscSection section, PetscSection globalSection, Mat A, PetscInt point, PetscScalar values[], InsertMode mode)
7971 {
7972   DM_Plex     *mesh   = (DM_Plex *) dm->data;
7973   PetscInt       *points = PETSC_NULL;
7974   PetscInt       *indices;
7975   PetscInt        offsets[32];
7976   PetscInt        numFields, numPoints, numIndices, dof, off, globalOff, pStart, pEnd, p, q, f;
7977   PetscBool       useDefault       =       !section ? PETSC_TRUE : PETSC_FALSE;
7978   PetscBool       useGlobalDefault = !globalSection ? PETSC_TRUE : PETSC_FALSE;
7979   PetscErrorCode  ierr;
7980 
7981   PetscFunctionBegin;
7982   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
7983   PetscValidHeaderSpecific(A, MAT_CLASSID, 3);
7984   if (useDefault) {
7985     ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
7986   }
7987   if (useGlobalDefault) {
7988     if (useDefault) {
7989       ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);
7990     } else {
7991       ierr = PetscSectionCreateGlobalSection(section, dm->sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
7992     }
7993   }
7994   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
7995   if (numFields > 31) SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of fields %D limited to 31", numFields);
7996   ierr = PetscMemzero(offsets, 32 * sizeof(PetscInt));CHKERRQ(ierr);
7997   ierr = DMPlexGetTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
7998   /* Compress out points not in the section */
7999   ierr = PetscSectionGetChart(section, &pStart, &pEnd);CHKERRQ(ierr);
8000   for (p = 0, q = 0; p < numPoints*2; p += 2) {
8001     if ((points[p] >= pStart) && (points[p] < pEnd)) {
8002       points[q*2]   = points[p];
8003       points[q*2+1] = points[p+1];
8004       ++q;
8005     }
8006   }
8007   numPoints = q;
8008   for (p = 0, numIndices = 0; p < numPoints*2; p += 2) {
8009     PetscInt fdof;
8010 
8011     ierr = PetscSectionGetDof(section, points[p], &dof);CHKERRQ(ierr);
8012     for (f = 0; f < numFields; ++f) {
8013       ierr = PetscSectionGetFieldDof(section, points[p], f, &fdof);CHKERRQ(ierr);
8014       offsets[f+1] += fdof;
8015     }
8016     numIndices += dof;
8017   }
8018   for (f = 1; f < numFields; ++f) {
8019     offsets[f+1] += offsets[f];
8020   }
8021   if (numFields && offsets[numFields] != numIndices) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_PLIB, "Invalid size for closure %d should be %d", offsets[numFields], numIndices);
8022   ierr = DMGetWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8023   if (numFields) {
8024     for (p = 0; p < numPoints*2; p += 2) {
8025       PetscInt o = points[p+1];
8026       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8027       indicesPointFields_private(section, points[p], globalOff < 0 ? -(globalOff+1) : globalOff, offsets, PETSC_FALSE, o, indices);
8028     }
8029   } else {
8030     for (p = 0, off = 0; p < numPoints*2; p += 2, off += dof) {
8031       PetscInt o = points[p+1];
8032       ierr = PetscSectionGetOffset(globalSection, points[p], &globalOff);CHKERRQ(ierr);
8033       indicesPoint_private(section, points[p], dof, globalOff < 0 ? -(globalOff+1) : globalOff, PETSC_FALSE, o, &indices[off]);
8034     }
8035   }
8036   if (useGlobalDefault && !useDefault) {
8037     ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
8038   }
8039   if (mesh->printSetValues) {ierr = DMPlexPrintMatSetValues(PETSC_VIEWER_STDOUT_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr);}
8040   ierr = MatSetValues(A, numIndices, indices, numIndices, indices, values, mode);
8041   if (ierr) {
8042     PetscMPIInt    rank;
8043     PetscErrorCode ierr2;
8044 
8045     ierr2 = MPI_Comm_rank(((PetscObject) A)->comm, &rank);CHKERRQ(ierr2);
8046     ierr2 = (*PetscErrorPrintf)("[%D]ERROR in DMPlexMatSetClosure\n", rank);CHKERRQ(ierr2);
8047     ierr2 = DMPlexPrintMatSetValues(PETSC_VIEWER_STDERR_SELF, A, point, numIndices, indices, values);CHKERRQ(ierr2);
8048     ierr2 = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr2);
8049     CHKERRQ(ierr);
8050   }
8051   ierr = DMPlexRestoreTransitiveClosure(dm, point, PETSC_TRUE, &numPoints, &points);CHKERRQ(ierr);
8052   ierr = DMRestoreWorkArray(dm, numIndices, PETSC_INT, &indices);CHKERRQ(ierr);
8053   PetscFunctionReturn(0);
8054 }
8055 
8056 #undef __FUNCT__
8057 #define __FUNCT__ "DMPlexComputeTriangleGeometry_private"
8058 PetscErrorCode DMPlexComputeTriangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8059 {
8060   PetscSection       coordSection;
8061   Vec                coordinates;
8062   const PetscScalar *coords;
8063   const PetscInt     dim = 2;
8064   PetscInt           d, f;
8065   PetscErrorCode     ierr;
8066 
8067   PetscFunctionBegin;
8068   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8069   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8070   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8071   if (v0) {
8072     for (d = 0; d < dim; d++) {
8073       v0[d] = PetscRealPart(coords[d]);
8074     }
8075   }
8076   if (J) {
8077     for (d = 0; d < dim; d++) {
8078       for (f = 0; f < dim; f++) {
8079         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8080       }
8081     }
8082     *detJ = J[0]*J[3] - J[1]*J[2];
8083 #if 0
8084     if (detJ < 0.0) {
8085       const PetscReal xLength = mesh->periodicity[0];
8086 
8087       if (xLength != 0.0) {
8088         PetscReal v0x = coords[0*dim+0];
8089 
8090         if (v0x == 0.0) {
8091           v0x = v0[0] = xLength;
8092         }
8093         for (f = 0; f < dim; f++) {
8094           const PetscReal px = coords[(f+1)*dim+0] == 0.0 ? xLength : coords[(f+1)*dim+0];
8095 
8096           J[0*dim+f] = 0.5*(px - v0x);
8097         }
8098       }
8099       detJ = J[0]*J[3] - J[1]*J[2];
8100     }
8101 #endif
8102     PetscLogFlops(8.0 + 3.0);
8103   }
8104   if (invJ) {
8105     const PetscReal invDet = 1.0/(*detJ);
8106 
8107     invJ[0] =  invDet*J[3];
8108     invJ[1] = -invDet*J[1];
8109     invJ[2] = -invDet*J[2];
8110     invJ[3] =  invDet*J[0];
8111     PetscLogFlops(5.0);
8112   }
8113   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8114   PetscFunctionReturn(0);
8115 }
8116 
8117 #undef __FUNCT__
8118 #define __FUNCT__ "DMPlexComputeRectangleGeometry_private"
8119 PetscErrorCode DMPlexComputeRectangleGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8120 {
8121   PetscSection       coordSection;
8122   Vec                coordinates;
8123   const PetscScalar *coords;
8124   const PetscInt     dim = 2;
8125   PetscInt           d, f;
8126   PetscErrorCode     ierr;
8127 
8128   PetscFunctionBegin;
8129   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8130   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8131   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8132   if (v0) {
8133     for (d = 0; d < dim; d++) {
8134       v0[d] = PetscRealPart(coords[d]);
8135     }
8136   }
8137   if (J) {
8138     for (d = 0; d < dim; d++) {
8139       for (f = 0; f < dim; f++) {
8140         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f*2+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8141       }
8142     }
8143     *detJ = J[0]*J[3] - J[1]*J[2];
8144     PetscLogFlops(8.0 + 3.0);
8145   }
8146   if (invJ) {
8147     const PetscReal invDet = 1.0/(*detJ);
8148 
8149     invJ[0] =  invDet*J[3];
8150     invJ[1] = -invDet*J[1];
8151     invJ[2] = -invDet*J[2];
8152     invJ[3] =  invDet*J[0];
8153     PetscLogFlops(5.0);
8154   }
8155   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8156   PetscFunctionReturn(0);
8157 }
8158 
8159 #undef __FUNCT__
8160 #define __FUNCT__ "DMPlexComputeTetrahedronGeometry_private"
8161 PetscErrorCode DMPlexComputeTetrahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8162 {
8163   PetscSection       coordSection;
8164   Vec                coordinates;
8165   const PetscScalar *coords;
8166   const PetscInt     dim = 3;
8167   PetscInt           d, f;
8168   PetscErrorCode     ierr;
8169 
8170   PetscFunctionBegin;
8171   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8172   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8173   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8174   if (v0) {
8175     for (d = 0; d < dim; d++) {
8176       v0[d] = PetscRealPart(coords[d]);
8177     }
8178   }
8179   if (J) {
8180     for (d = 0; d < dim; d++) {
8181       for (f = 0; f < dim; f++) {
8182         J[d*dim+f] = 0.5*(PetscRealPart(coords[(f+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8183       }
8184     }
8185     /* ??? This does not work with CTetGen: The minus sign is here since I orient the first face to get the outward normal */
8186     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8187              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8188              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8189     PetscLogFlops(18.0 + 12.0);
8190   }
8191   if (invJ) {
8192     const PetscReal invDet = -1.0/(*detJ);
8193 
8194     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8195     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8196     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8197     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8198     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8199     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8200     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8201     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8202     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8203     PetscLogFlops(37.0);
8204   }
8205   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8206   PetscFunctionReturn(0);
8207 }
8208 
8209 #undef __FUNCT__
8210 #define __FUNCT__ "DMPlexComputeHexahedronGeometry_private"
8211 PetscErrorCode DMPlexComputeHexahedronGeometry_private(DM dm, PetscInt e, PetscReal v0[], PetscReal J[], PetscReal invJ[], PetscReal *detJ)
8212 {
8213   PetscSection       coordSection;
8214   Vec                coordinates;
8215   const PetscScalar *coords;
8216   const PetscInt     dim = 3;
8217   PetscInt           d;
8218   PetscErrorCode     ierr;
8219 
8220   PetscFunctionBegin;
8221   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8222   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8223   ierr = DMPlexVecGetClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8224   if (v0) {
8225     for (d = 0; d < dim; d++) {
8226       v0[d] = PetscRealPart(coords[d]);
8227     }
8228   }
8229   if (J) {
8230     for (d = 0; d < dim; d++) {
8231       J[d*dim+0] = 0.5*(PetscRealPart(coords[(0+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8232       J[d*dim+1] = 0.5*(PetscRealPart(coords[(1+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8233       J[d*dim+2] = 0.5*(PetscRealPart(coords[(3+1)*dim+d]) - PetscRealPart(coords[0*dim+d]));
8234     }
8235     *detJ = (J[0*3+0]*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]) +
8236              J[0*3+1]*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]) +
8237              J[0*3+2]*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]));
8238     PetscLogFlops(18.0 + 12.0);
8239   }
8240   if (invJ) {
8241     const PetscReal invDet = -1.0/(*detJ);
8242 
8243     invJ[0*3+0] = invDet*(J[1*3+1]*J[2*3+2] - J[1*3+2]*J[2*3+1]);
8244     invJ[0*3+1] = invDet*(J[0*3+2]*J[2*3+1] - J[0*3+1]*J[2*3+2]);
8245     invJ[0*3+2] = invDet*(J[0*3+1]*J[1*3+2] - J[0*3+2]*J[1*3+1]);
8246     invJ[1*3+0] = invDet*(J[1*3+2]*J[2*3+0] - J[1*3+0]*J[2*3+2]);
8247     invJ[1*3+1] = invDet*(J[0*3+0]*J[2*3+2] - J[0*3+2]*J[2*3+0]);
8248     invJ[1*3+2] = invDet*(J[0*3+2]*J[1*3+0] - J[0*3+0]*J[1*3+2]);
8249     invJ[2*3+0] = invDet*(J[1*3+0]*J[2*3+1] - J[1*3+1]*J[2*3+0]);
8250     invJ[2*3+1] = invDet*(J[0*3+1]*J[2*3+0] - J[0*3+0]*J[2*3+1]);
8251     invJ[2*3+2] = invDet*(J[0*3+0]*J[1*3+1] - J[0*3+1]*J[1*3+0]);
8252     PetscLogFlops(37.0);
8253   }
8254   *detJ *= 8.0;
8255   ierr = DMPlexVecRestoreClosure(dm, coordSection, coordinates, e, PETSC_NULL, &coords);CHKERRQ(ierr);
8256   PetscFunctionReturn(0);
8257 }
8258 
8259 #undef __FUNCT__
8260 #define __FUNCT__ "DMPlexComputeCellGeometry"
8261 /*@C
8262   DMPlexComputeCellGeometry - Compute the Jacobian, inverse Jacobian, and Jacobian determinant for a given cell
8263 
8264   Collective on DM
8265 
8266   Input Arguments:
8267 + dm   - the DM
8268 - cell - the cell
8269 
8270   Output Arguments:
8271 + v0   - the translation part of this affine transform
8272 . J    - the Jacobian of the transform to the reference element
8273 . invJ - the inverse of the Jacobian
8274 - detJ - the Jacobian determinant
8275 
8276   Level: advanced
8277 
8278 .seealso: DMPlexGetCoordinateSection(), DMPlexGetCoordinateVec()
8279 @*/
8280 PetscErrorCode DMPlexComputeCellGeometry(DM dm, PetscInt cell, PetscReal *v0, PetscReal *J, PetscReal *invJ, PetscReal *detJ) {
8281   PetscInt       dim, maxConeSize;
8282   PetscErrorCode ierr;
8283 
8284   PetscFunctionBegin;
8285   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8286   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
8287   switch(dim) {
8288   case 2:
8289     switch(maxConeSize) {
8290     case 3:
8291       ierr = DMPlexComputeTriangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8292       break;
8293     case 4:
8294       ierr = DMPlexComputeRectangleGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8295       break;
8296     default:
8297       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of cell vertices %D for element geometry computation", maxConeSize);
8298     }
8299     break;
8300   case 3:
8301     switch(maxConeSize) {
8302     case 4:
8303       ierr = DMPlexComputeTetrahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8304       break;
8305     case 8:
8306       ierr = DMPlexComputeHexahedronGeometry_private(dm, cell, v0, J, invJ, detJ);CHKERRQ(ierr);
8307       break;
8308     default:
8309       SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported number of cell vertices %D for element geometry computation", maxConeSize);
8310     }
8311     break;
8312   default:
8313     SETERRQ1(((PetscObject) dm)->comm, PETSC_ERR_SUP, "Unsupported dimension %D for element geometry computation", dim);
8314   }
8315   PetscFunctionReturn(0);
8316 }
8317 
8318 #undef __FUNCT__
8319 #define __FUNCT__ "DMPlexGetFaceOrientation"
8320 PetscErrorCode DMPlexGetFaceOrientation(DM dm, PetscInt cell, PetscInt numCorners, PetscInt indices[], PetscInt oppositeVertex, PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented) {
8321   MPI_Comm       comm      = ((PetscObject) dm)->comm;
8322   PetscBool      posOrient = PETSC_FALSE;
8323   const PetscInt debug     = 0;
8324   PetscInt       cellDim, faceSize, f;
8325   PetscErrorCode ierr;
8326 
8327   ierr = DMPlexGetDimension(dm, &cellDim);CHKERRQ(ierr);
8328   if (debug) {PetscPrintf(comm, "cellDim: %d numCorners: %d\n", cellDim, numCorners);CHKERRQ(ierr);}
8329 
8330   if (cellDim == numCorners-1) {
8331     /* Simplices */
8332     faceSize  = numCorners-1;
8333     posOrient = !(oppositeVertex%2) ? PETSC_TRUE : PETSC_FALSE;
8334   } else if (cellDim == 1 && numCorners == 3) {
8335     /* Quadratic line */
8336     faceSize  = 1;
8337     posOrient = PETSC_TRUE;
8338   } else if (cellDim == 2 && numCorners == 4) {
8339     /* Quads */
8340     faceSize  = 2;
8341     if ((indices[1] > indices[0]) && (indices[1] - indices[0] == 1)) {
8342       posOrient = PETSC_TRUE;
8343     } else if ((indices[0] == 3) && (indices[1] == 0)) {
8344       posOrient = PETSC_TRUE;
8345     } else {
8346       if (((indices[0] > indices[1]) && (indices[0] - indices[1] == 1)) || ((indices[0] == 0) && (indices[1] == 3))) {
8347         posOrient = PETSC_FALSE;
8348       } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossedge");
8349     }
8350   } else if (cellDim == 2 && numCorners == 6) {
8351     /* Quadratic triangle (I hate this) */
8352     /* Edges are determined by the first 2 vertices (corners of edges) */
8353     const PetscInt faceSizeTri = 3;
8354     PetscInt  sortedIndices[3], i, iFace;
8355     PetscBool found = PETSC_FALSE;
8356     PetscInt  faceVerticesTriSorted[9] = {
8357       0, 3,  4, /* bottom */
8358       1, 4,  5, /* right */
8359       2, 3,  5, /* left */
8360     };
8361     PetscInt  faceVerticesTri[9] = {
8362       0, 3,  4, /* bottom */
8363       1, 4,  5, /* right */
8364       2, 5,  3, /* left */
8365     };
8366 
8367     faceSize = faceSizeTri;
8368     for (i = 0; i < faceSizeTri; ++i) sortedIndices[i] = indices[i];
8369     ierr = PetscSortInt(faceSizeTri, sortedIndices);CHKERRQ(ierr);
8370     for (iFace = 0; iFace < 3; ++iFace) {
8371       const PetscInt ii = iFace*faceSizeTri;
8372       PetscInt       fVertex, cVertex;
8373 
8374       if ((sortedIndices[0] == faceVerticesTriSorted[ii+0]) &&
8375           (sortedIndices[1] == faceVerticesTriSorted[ii+1])) {
8376         for (fVertex = 0; fVertex < faceSizeTri; ++fVertex) {
8377           for (cVertex = 0; cVertex < faceSizeTri; ++cVertex) {
8378             if (indices[cVertex] == faceVerticesTri[ii+fVertex]) {
8379               faceVertices[fVertex] = origVertices[cVertex];
8380               break;
8381             }
8382           }
8383         }
8384         found = PETSC_TRUE;
8385         break;
8386       }
8387     }
8388     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tri crossface");
8389     if (posOriented) {*posOriented = PETSC_TRUE;}
8390     PetscFunctionReturn(0);
8391   } else if (cellDim == 2 && numCorners == 9) {
8392     /* Quadratic quad (I hate this) */
8393     /* Edges are determined by the first 2 vertices (corners of edges) */
8394     const PetscInt faceSizeQuad = 3;
8395     PetscInt  sortedIndices[3], i, iFace;
8396     PetscBool found = PETSC_FALSE;
8397     PetscInt  faceVerticesQuadSorted[12] = {
8398       0, 1,  4, /* bottom */
8399       1, 2,  5, /* right */
8400       2, 3,  6, /* top */
8401       0, 3,  7, /* left */
8402     };
8403     PetscInt  faceVerticesQuad[12] = {
8404       0, 1,  4, /* bottom */
8405       1, 2,  5, /* right */
8406       2, 3,  6, /* top */
8407       3, 0,  7, /* left */
8408     };
8409 
8410     faceSize = faceSizeQuad;
8411     for (i = 0; i < faceSizeQuad; ++i) sortedIndices[i] = indices[i];
8412     ierr = PetscSortInt(faceSizeQuad, sortedIndices);CHKERRQ(ierr);
8413     for (iFace = 0; iFace < 4; ++iFace) {
8414       const PetscInt ii = iFace*faceSizeQuad;
8415       PetscInt       fVertex, cVertex;
8416 
8417       if ((sortedIndices[0] == faceVerticesQuadSorted[ii+0]) &&
8418           (sortedIndices[1] == faceVerticesQuadSorted[ii+1])) {
8419         for (fVertex = 0; fVertex < faceSizeQuad; ++fVertex) {
8420           for (cVertex = 0; cVertex < faceSizeQuad; ++cVertex) {
8421             if (indices[cVertex] == faceVerticesQuad[ii+fVertex]) {
8422               faceVertices[fVertex] = origVertices[cVertex];
8423               break;
8424             }
8425           }
8426         }
8427         found = PETSC_TRUE;
8428         break;
8429       }
8430     }
8431     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid quad crossface");
8432     if (posOriented) {*posOriented = PETSC_TRUE;}
8433     PetscFunctionReturn(0);
8434   } else if (cellDim == 3 && numCorners == 8) {
8435     /* Hexes
8436        A hex is two oriented quads with the normal of the first
8437        pointing up at the second.
8438 
8439           7---6
8440          /|  /|
8441         4---5 |
8442         | 3-|-2
8443         |/  |/
8444         0---1
8445 
8446         Faces are determined by the first 4 vertices (corners of faces) */
8447     const PetscInt faceSizeHex = 4;
8448     PetscInt  sortedIndices[4], i, iFace;
8449     PetscBool found = PETSC_FALSE;
8450     PetscInt faceVerticesHexSorted[24] = {
8451       0, 1, 2, 3,  /* bottom */
8452       4, 5, 6, 7,  /* top */
8453       0, 1, 4, 5,  /* front */
8454       1, 2, 5, 6,  /* right */
8455       2, 3, 6, 7,  /* back */
8456       0, 3, 4, 7,  /* left */
8457     };
8458     PetscInt faceVerticesHex[24] = {
8459       3, 2, 1, 0,  /* bottom */
8460       4, 5, 6, 7,  /* top */
8461       0, 1, 5, 4,  /* front */
8462       1, 2, 6, 5,  /* right */
8463       2, 3, 7, 6,  /* back */
8464       3, 0, 4, 7,  /* left */
8465     };
8466 
8467     faceSize = faceSizeHex;
8468     for (i = 0; i < faceSizeHex; ++i) sortedIndices[i] = indices[i];
8469     ierr = PetscSortInt(faceSizeHex, sortedIndices);CHKERRQ(ierr);
8470     for (iFace = 0; iFace < 6; ++iFace) {
8471       const PetscInt ii = iFace*faceSizeHex;
8472       PetscInt       fVertex, cVertex;
8473 
8474       if ((sortedIndices[0] == faceVerticesHexSorted[ii+0]) &&
8475           (sortedIndices[1] == faceVerticesHexSorted[ii+1]) &&
8476           (sortedIndices[2] == faceVerticesHexSorted[ii+2]) &&
8477           (sortedIndices[3] == faceVerticesHexSorted[ii+3])) {
8478         for (fVertex = 0; fVertex < faceSizeHex; ++fVertex) {
8479           for (cVertex = 0; cVertex < faceSizeHex; ++cVertex) {
8480             if (indices[cVertex] == faceVerticesHex[ii+fVertex]) {
8481               faceVertices[fVertex] = origVertices[cVertex];
8482               break;
8483             }
8484           }
8485         }
8486         found = PETSC_TRUE;
8487         break;
8488       }
8489     }
8490     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
8491     if (posOriented) {*posOriented = PETSC_TRUE;}
8492     PetscFunctionReturn(0);
8493   } else if (cellDim == 3 && numCorners == 10) {
8494     /* Quadratic tet */
8495     /* Faces are determined by the first 3 vertices (corners of faces) */
8496     const PetscInt faceSizeTet = 6;
8497     PetscInt  sortedIndices[6], i, iFace;
8498     PetscBool found = PETSC_FALSE;
8499     PetscInt faceVerticesTetSorted[24] = {
8500       0, 1, 2,  6, 7, 8, /* bottom */
8501       0, 3, 4,  6, 7, 9,  /* front */
8502       1, 4, 5,  7, 8, 9,  /* right */
8503       2, 3, 5,  6, 8, 9,  /* left */
8504     };
8505     PetscInt faceVerticesTet[24] = {
8506       0, 1, 2,  6, 7, 8, /* bottom */
8507       0, 4, 3,  6, 7, 9,  /* front */
8508       1, 5, 4,  7, 8, 9,  /* right */
8509       2, 3, 5,  8, 6, 9,  /* left */
8510     };
8511 
8512     faceSize = faceSizeTet;
8513     for (i = 0; i < faceSizeTet; ++i) sortedIndices[i] = indices[i];
8514     ierr = PetscSortInt(faceSizeTet, sortedIndices);CHKERRQ(ierr);
8515     for (iFace=0; iFace < 4; ++iFace) {
8516       const PetscInt ii = iFace*faceSizeTet;
8517       PetscInt       fVertex, cVertex;
8518 
8519       if ((sortedIndices[0] == faceVerticesTetSorted[ii+0]) &&
8520           (sortedIndices[1] == faceVerticesTetSorted[ii+1]) &&
8521           (sortedIndices[2] == faceVerticesTetSorted[ii+2]) &&
8522           (sortedIndices[3] == faceVerticesTetSorted[ii+3])) {
8523         for (fVertex = 0; fVertex < faceSizeTet; ++fVertex) {
8524           for (cVertex = 0; cVertex < faceSizeTet; ++cVertex) {
8525             if (indices[cVertex] == faceVerticesTet[ii+fVertex]) {
8526               faceVertices[fVertex] = origVertices[cVertex];
8527               break;
8528             }
8529           }
8530         }
8531         found = PETSC_TRUE;
8532         break;
8533       }
8534     }
8535     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid tet crossface");
8536     if (posOriented) {*posOriented = PETSC_TRUE;}
8537     PetscFunctionReturn(0);
8538   } else if (cellDim == 3 && numCorners == 27) {
8539     /* Quadratic hexes (I hate this)
8540        A hex is two oriented quads with the normal of the first
8541        pointing up at the second.
8542 
8543          7---6
8544         /|  /|
8545        4---5 |
8546        | 3-|-2
8547        |/  |/
8548        0---1
8549 
8550        Faces are determined by the first 4 vertices (corners of faces) */
8551     const PetscInt faceSizeQuadHex = 9;
8552     PetscInt  sortedIndices[9], i, iFace;
8553     PetscBool found = PETSC_FALSE;
8554     PetscInt faceVerticesQuadHexSorted[54] = {
8555       0, 1, 2, 3,  8, 9, 10, 11,  24, /* bottom */
8556       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
8557       0, 1, 4, 5,  8, 12, 16, 17,  22, /* front */
8558       1, 2, 5, 6,  9, 13, 17, 18,  21, /* right */
8559       2, 3, 6, 7,  10, 14, 18, 19,  23, /* back */
8560       0, 3, 4, 7,  11, 15, 16, 19,  20, /* left */
8561     };
8562     PetscInt faceVerticesQuadHex[54] = {
8563       3, 2, 1, 0,  10, 9, 8, 11,  24, /* bottom */
8564       4, 5, 6, 7,  12, 13, 14, 15,  25, /* top */
8565       0, 1, 5, 4,  8, 17, 12, 16,  22, /* front */
8566       1, 2, 6, 5,  9, 18, 13, 17,  21, /* right */
8567       2, 3, 7, 6,  10, 19, 14, 18,  23, /* back */
8568       3, 0, 4, 7,  11, 16, 15, 19,  20 /* left */
8569     };
8570 
8571     faceSize = faceSizeQuadHex;
8572     for (i = 0; i < faceSizeQuadHex; ++i) sortedIndices[i] = indices[i];
8573     ierr = PetscSortInt(faceSizeQuadHex, sortedIndices);CHKERRQ(ierr);
8574     for (iFace = 0; iFace < 6; ++iFace) {
8575       const PetscInt ii = iFace*faceSizeQuadHex;
8576       PetscInt       fVertex, cVertex;
8577 
8578       if ((sortedIndices[0] == faceVerticesQuadHexSorted[ii+0]) &&
8579           (sortedIndices[1] == faceVerticesQuadHexSorted[ii+1]) &&
8580           (sortedIndices[2] == faceVerticesQuadHexSorted[ii+2]) &&
8581           (sortedIndices[3] == faceVerticesQuadHexSorted[ii+3])) {
8582         for (fVertex = 0; fVertex < faceSizeQuadHex; ++fVertex) {
8583           for (cVertex = 0; cVertex < faceSizeQuadHex; ++cVertex) {
8584             if (indices[cVertex] == faceVerticesQuadHex[ii+fVertex]) {
8585               faceVertices[fVertex] = origVertices[cVertex];
8586               break;
8587             }
8588           }
8589         }
8590         found = PETSC_TRUE;
8591         break;
8592       }
8593     }
8594     if (!found) SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Invalid hex crossface");
8595     if (posOriented) {*posOriented = PETSC_TRUE;}
8596     PetscFunctionReturn(0);
8597   } else SETERRQ(comm, PETSC_ERR_ARG_WRONG, "Unknown cell type for faceOrientation().");
8598   if (!posOrient) {
8599     if (debug) {ierr = PetscPrintf(comm, "  Reversing initial face orientation\n");CHKERRQ(ierr);}
8600     for (f = 0; f < faceSize; ++f) {
8601       faceVertices[f] = origVertices[faceSize-1 - f];
8602     }
8603   } else {
8604     if (debug) {ierr = PetscPrintf(comm, "  Keeping initial face orientation\n");CHKERRQ(ierr);}
8605     for (f = 0; f < faceSize; ++f) {
8606       faceVertices[f] = origVertices[f];
8607     }
8608   }
8609   if (posOriented) {*posOriented = posOrient;}
8610   PetscFunctionReturn(0);
8611 }
8612 
8613 #undef __FUNCT__
8614 #define __FUNCT__ "DMPlexGetOrientedFace"
8615 /*
8616     Given a cell and a face, as a set of vertices,
8617       return the oriented face, as a set of vertices, in faceVertices
8618     The orientation is such that the face normal points out of the cell
8619 */
8620 PetscErrorCode DMPlexGetOrientedFace(DM dm, PetscInt cell, PetscInt faceSize, const PetscInt face[], PetscInt numCorners, PetscInt indices[], PetscInt origVertices[], PetscInt faceVertices[], PetscBool *posOriented)
8621 {
8622   const PetscInt *cone = PETSC_NULL;
8623   PetscInt        coneSize, v, f, v2;
8624   PetscInt        oppositeVertex = -1;
8625   PetscErrorCode  ierr;
8626 
8627   PetscFunctionBegin;
8628   ierr = DMPlexGetConeSize(dm, cell, &coneSize);CHKERRQ(ierr);
8629   ierr = DMPlexGetCone(dm, cell, &cone);CHKERRQ(ierr);
8630   for (v = 0, v2 = 0; v < coneSize; ++v) {
8631     PetscBool found  = PETSC_FALSE;
8632 
8633     for (f = 0; f < faceSize; ++f) {
8634       if (face[f] == cone[v]) {found = PETSC_TRUE; break;}
8635     }
8636     if (found) {
8637       indices[v2]      = v;
8638       origVertices[v2] = cone[v];
8639       ++v2;
8640     } else {
8641       oppositeVertex = v;
8642     }
8643   }
8644   ierr = DMPlexGetFaceOrientation(dm, cell, numCorners, indices, oppositeVertex, origVertices, faceVertices, posOriented);CHKERRQ(ierr);
8645   PetscFunctionReturn(0);
8646 }
8647 
8648 PETSC_STATIC_INLINE PetscInt epsilon(PetscInt i, PetscInt j, PetscInt k)
8649 {
8650   switch(i) {
8651   case 0:
8652     switch(j) {
8653     case 0: return 0;
8654     case 1:
8655       switch(k) {
8656       case 0: return 0;
8657       case 1: return 0;
8658       case 2: return 1;
8659       }
8660     case 2:
8661       switch(k) {
8662       case 0: return 0;
8663       case 1: return -1;
8664       case 2: return 0;
8665       }
8666     }
8667   case 1:
8668     switch(j) {
8669     case 0:
8670       switch(k) {
8671       case 0: return 0;
8672       case 1: return 0;
8673       case 2: return -1;
8674       }
8675     case 1: return 0;
8676     case 2:
8677       switch(k) {
8678       case 0: return 1;
8679       case 1: return 0;
8680       case 2: return 0;
8681       }
8682     }
8683   case 2:
8684     switch(j) {
8685     case 0:
8686       switch(k) {
8687       case 0: return 0;
8688       case 1: return 1;
8689       case 2: return 0;
8690       }
8691     case 1:
8692       switch(k) {
8693       case 0: return -1;
8694       case 1: return 0;
8695       case 2: return 0;
8696       }
8697     case 2: return 0;
8698     }
8699   }
8700   return 0;
8701 }
8702 
8703 #undef __FUNCT__
8704 #define __FUNCT__ "DMPlexCreateRigidBody"
8705 /*@C
8706   DMPlexCreateRigidBody - create rigid body modes from coordinates
8707 
8708   Collective on DM
8709 
8710   Input Arguments:
8711 + dm - the DM
8712 . section - the local section associated with the rigid field, or PETSC_NULL for the default section
8713 - globalSection - the global section associated with the rigid field, or PETSC_NULL for the default section
8714 
8715   Output Argument:
8716 . sp - the null space
8717 
8718   Note: This is necessary to take account of Dirichlet conditions on the displacements
8719 
8720   Level: advanced
8721 
8722 .seealso: MatNullSpaceCreate()
8723 @*/
8724 PetscErrorCode DMPlexCreateRigidBody(DM dm, PetscSection section, PetscSection globalSection, MatNullSpace *sp)
8725 {
8726   MPI_Comm       comm = ((PetscObject) dm)->comm;
8727   Vec            coordinates, localMode, mode[6];
8728   PetscSection   coordSection;
8729   PetscScalar   *coords;
8730   PetscInt       dim, vStart, vEnd, v, n, m, d, i, j;
8731   PetscErrorCode ierr;
8732 
8733   PetscFunctionBegin;
8734   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8735   if (dim == 1) {
8736     ierr = MatNullSpaceCreate(comm, PETSC_TRUE, 0, PETSC_NULL, sp);CHKERRQ(ierr);
8737     PetscFunctionReturn(0);
8738   }
8739   if (!section)       {ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);}
8740   if (!globalSection) {ierr = DMGetDefaultGlobalSection(dm, &globalSection);CHKERRQ(ierr);}
8741   ierr = PetscSectionGetConstrainedStorageSize(globalSection, &n);CHKERRQ(ierr);
8742   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8743   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
8744   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
8745   m    = (dim*(dim+1))/2;
8746   ierr = VecCreate(comm, &mode[0]);CHKERRQ(ierr);
8747   ierr = VecSetSizes(mode[0], n, PETSC_DETERMINE);CHKERRQ(ierr);
8748   ierr = VecSetUp(mode[0]);CHKERRQ(ierr);
8749   for (i = 1; i < m; ++i) {ierr = VecDuplicate(mode[0], &mode[i]);CHKERRQ(ierr);}
8750   /* Assume P1 */
8751   ierr = DMGetLocalVector(dm, &localMode);CHKERRQ(ierr);
8752   for (d = 0; d < dim; ++d) {
8753     PetscScalar values[3] = {0.0, 0.0, 0.0};
8754 
8755     values[d] = 1.0;
8756     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8757     for (v = vStart; v < vEnd; ++v) {
8758       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8759     }
8760     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8761     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8762   }
8763   ierr = VecGetArray(coordinates, &coords);CHKERRQ(ierr);
8764   for (d = dim; d < dim*(dim+1)/2; ++d) {
8765     PetscInt i, j, k = dim > 2 ? d - dim : d;
8766 
8767     ierr = VecSet(localMode, 0.0);CHKERRQ(ierr);
8768     for (v = vStart; v < vEnd; ++v) {
8769       PetscScalar values[3] = {0.0, 0.0, 0.0};
8770       PetscInt    off;
8771 
8772       ierr = PetscSectionGetOffset(coordSection, v, &off);CHKERRQ(ierr);
8773       for (i = 0; i < dim; ++i) {
8774         for (j = 0; j < dim; ++j) {
8775           values[j] += epsilon(i, j, k)*PetscRealPart(coords[off+i]);
8776         }
8777       }
8778       ierr = DMPlexVecSetClosure(dm, section, localMode, v, values, INSERT_VALUES);CHKERRQ(ierr);
8779     }
8780     ierr = DMLocalToGlobalBegin(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8781     ierr = DMLocalToGlobalEnd(dm, localMode, INSERT_VALUES, mode[d]);CHKERRQ(ierr);
8782   }
8783   ierr = VecRestoreArray(coordinates, &coords);CHKERRQ(ierr);
8784   ierr = DMRestoreLocalVector(dm, &localMode);CHKERRQ(ierr);
8785   for (i = 0; i < dim; ++i) {ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);}
8786   /* Orthonormalize system */
8787   for (i = dim; i < m; ++i) {
8788     PetscScalar dots[6];
8789 
8790     ierr = VecMDot(mode[i], i, mode, dots);CHKERRQ(ierr);
8791     for (j = 0; j < i; ++j) dots[j] *= -1.0;
8792     ierr = VecMAXPY(mode[i], i, dots, mode);CHKERRQ(ierr);
8793     ierr = VecNormalize(mode[i], PETSC_NULL);CHKERRQ(ierr);
8794   }
8795   ierr = MatNullSpaceCreate(comm, PETSC_FALSE, m, mode, sp);CHKERRQ(ierr);
8796   for (i = 0; i< m; ++i) {ierr = VecDestroy(&mode[i]);CHKERRQ(ierr);}
8797   PetscFunctionReturn(0);
8798 }
8799 
8800 #undef __FUNCT__
8801 #define __FUNCT__ "DMPlexGetVTKBounds"
8802 PetscErrorCode DMPlexGetVTKBounds(DM dm, PetscInt *cMax, PetscInt *vMax)
8803 {
8804   DM_Plex *mesh = (DM_Plex *) dm->data;
8805 
8806   PetscFunctionBegin;
8807   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8808   if (cMax) *cMax = mesh->vtkCellMax;
8809   if (vMax) *vMax = mesh->vtkVertexMax;
8810   PetscFunctionReturn(0);
8811 }
8812 
8813 #undef __FUNCT__
8814 #define __FUNCT__ "DMPlexSetVTKBounds"
8815 PetscErrorCode DMPlexSetVTKBounds(DM dm, PetscInt cMax, PetscInt vMax)
8816 {
8817   DM_Plex *mesh = (DM_Plex *) dm->data;
8818 
8819   PetscFunctionBegin;
8820   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8821   if (cMax >= 0) mesh->vtkCellMax   = cMax;
8822   if (vMax >= 0) mesh->vtkVertexMax = vMax;
8823   PetscFunctionReturn(0);
8824 }
8825 
8826 #undef __FUNCT__
8827 #define __FUNCT__ "DMPlexGetVTKCellHeight"
8828 PetscErrorCode DMPlexGetVTKCellHeight(DM dm, PetscInt *cellHeight)
8829 {
8830   DM_Plex *mesh = (DM_Plex *) dm->data;
8831 
8832   PetscFunctionBegin;
8833   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8834   PetscValidPointer(cellHeight, 2);
8835   *cellHeight = mesh->vtkCellHeight;
8836   PetscFunctionReturn(0);
8837 }
8838 
8839 #undef __FUNCT__
8840 #define __FUNCT__ "DMPlexSetVTKCellHeight"
8841 PetscErrorCode DMPlexSetVTKCellHeight(DM dm, PetscInt cellHeight)
8842 {
8843   DM_Plex *mesh = (DM_Plex *) dm->data;
8844 
8845   PetscFunctionBegin;
8846   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
8847   mesh->vtkCellHeight = cellHeight;
8848   PetscFunctionReturn(0);
8849 }
8850 
8851 #undef __FUNCT__
8852 #define __FUNCT__ "DMPlexInsertFace_Private"
8853 /*
8854   DMPlexInsertFace_Private - Puts a face into the mesh
8855 
8856   Not collective
8857 
8858   Input Parameters:
8859   + dm              - The DMPlex
8860   . numFaceVertex   - The number of vertices in the face
8861   . faceVertices    - The vertices in the face for dm
8862   . subfaceVertices - The vertices in the face for subdm
8863   . numCorners      - The number of vertices in the cell
8864   . cell            - A cell in dm containing the face
8865   . subcell         - A cell in subdm containing the face
8866   . firstFace       - First face in the mesh
8867   - newFacePoint    - Next face in the mesh
8868 
8869   Output Parameters:
8870   . newFacePoint - Contains next face point number on input, updated on output
8871 
8872   Level: developer
8873 */
8874 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)
8875 {
8876   MPI_Comm        comm    = ((PetscObject) dm)->comm;
8877   DM_Plex     *submesh = (DM_Plex *) subdm->data;
8878   const PetscInt *faces;
8879   PetscInt        numFaces, coneSize;
8880   PetscErrorCode  ierr;
8881 
8882   PetscFunctionBegin;
8883   ierr = DMPlexGetConeSize(subdm, subcell, &coneSize);CHKERRQ(ierr);
8884   if (coneSize != 1) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Cone size of cell %d is %d != 1", cell, coneSize);
8885 #if 0
8886   /* Cannot use this because support() has not been constructed yet */
8887   ierr = DMPlexGetJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
8888 #else
8889   {
8890     PetscInt f;
8891 
8892     numFaces = 0;
8893     ierr = DMGetWorkArray(subdm, 1, PETSC_INT, (void **) &faces);CHKERRQ(ierr);
8894     for(f = firstFace; f < *newFacePoint; ++f) {
8895       PetscInt dof, off, d;
8896 
8897       ierr = PetscSectionGetDof(submesh->coneSection, f, &dof);CHKERRQ(ierr);
8898       ierr = PetscSectionGetOffset(submesh->coneSection, f, &off);CHKERRQ(ierr);
8899       /* Yes, I know this is quadratic, but I expect the sizes to be <5 */
8900       for(d = 0; d < dof; ++d) {
8901         const PetscInt p = submesh->cones[off+d];
8902         PetscInt       v;
8903 
8904         for(v = 0; v < numFaceVertices; ++v) {
8905           if (subfaceVertices[v] == p) break;
8906         }
8907         if (v == numFaceVertices) break;
8908       }
8909       if (d == dof) {
8910         numFaces = 1;
8911         ((PetscInt *) faces)[0] = f;
8912       }
8913     }
8914   }
8915 #endif
8916   if (numFaces > 1) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Vertex set had %d faces, not one", numFaces);
8917   else if (numFaces == 1) {
8918     /* Add the other cell neighbor for this face */
8919     ierr = DMPlexSetCone(subdm, cell, faces);CHKERRQ(ierr);
8920   } else {
8921     PetscInt *indices, *origVertices, *orientedVertices, *orientedSubVertices, v, ov;
8922     PetscBool posOriented;
8923 
8924     ierr = DMGetWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
8925     origVertices = &orientedVertices[numFaceVertices];
8926     indices      = &orientedVertices[numFaceVertices*2];
8927     orientedSubVertices = &orientedVertices[numFaceVertices*3];
8928     ierr = DMPlexGetOrientedFace(dm, cell, numFaceVertices, faceVertices, numCorners, indices, origVertices, orientedVertices, &posOriented);CHKERRQ(ierr);
8929     /* TODO: I know that routine should return a permutation, not the indices */
8930     for(v = 0; v < numFaceVertices; ++v) {
8931       const PetscInt vertex = faceVertices[v], subvertex = subfaceVertices[v];
8932       for(ov = 0; ov < numFaceVertices; ++ov) {
8933         if (orientedVertices[ov] == vertex) {
8934           orientedSubVertices[ov] = subvertex;
8935           break;
8936         }
8937       }
8938       if (ov == numFaceVertices) SETERRQ1(comm, PETSC_ERR_PLIB, "Could not find face vertex %d in orientated set", vertex);
8939     }
8940     ierr = DMPlexSetCone(subdm, *newFacePoint, orientedSubVertices);CHKERRQ(ierr);
8941     ierr = DMPlexSetCone(subdm, subcell, newFacePoint);CHKERRQ(ierr);
8942     ierr = DMRestoreWorkArray(subdm, 4*numFaceVertices * sizeof(PetscInt), PETSC_INT, &orientedVertices);CHKERRQ(ierr);
8943     ++(*newFacePoint);
8944   }
8945   ierr = DMPlexRestoreJoin(subdm, numFaceVertices, subfaceVertices, &numFaces, &faces);CHKERRQ(ierr);
8946   PetscFunctionReturn(0);
8947 }
8948 
8949 #undef __FUNCT__
8950 #define __FUNCT__ "DMPlexCreateSubmesh"
8951 PetscErrorCode DMPlexCreateSubmesh(DM dm, const char label[], DM *subdm)
8952 {
8953   MPI_Comm        comm = ((PetscObject) dm)->comm;
8954   DM_Plex     *submesh;
8955   PetscBool       boundaryFaces = PETSC_FALSE;
8956   PetscSection    coordSection, subCoordSection;
8957   Vec             coordinates, subCoordinates;
8958   PetscScalar    *coords, *subCoords;
8959   IS              labelIS;
8960   const PetscInt *subVertices;
8961   PetscInt       *subVerticesActive, *tmpPoints;
8962   PetscInt       *subCells = PETSC_NULL;
8963   PetscInt        numSubVertices, numSubVerticesActive, firstSubVertex, numSubCells = 0, maxSubCells = 0, numOldSubCells;
8964   PetscInt       *face, *subface, maxConeSize, numSubFaces = 0, firstSubFace, newFacePoint, nFV = 0, coordSize;
8965   PetscInt        dim; /* Right now, do not specify dimension */
8966   PetscInt        cStart, cEnd, cMax, c, vStart, vEnd, vMax, v, p, corner, i, d, f;
8967   PetscErrorCode  ierr;
8968 
8969   PetscFunctionBegin;
8970   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
8971   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
8972   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
8973   ierr = DMPlexGetMaxSizes(dm, &maxConeSize, PETSC_NULL);CHKERRQ(ierr);
8974   ierr = DMPlexGetVTKBounds(dm, &cMax, &vMax);CHKERRQ(ierr);
8975   if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
8976   if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
8977   ierr = DMGetWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
8978   subface = &face[maxConeSize];
8979   ierr = DMCreate(comm, subdm);CHKERRQ(ierr);
8980   ierr = DMSetType(*subdm, DMPLEX);CHKERRQ(ierr);
8981   ierr = DMPlexSetDimension(*subdm, dim-1);CHKERRQ(ierr);
8982   ierr = DMPlexGetStratumIS(dm, label, 1, &labelIS);CHKERRQ(ierr);
8983   ierr = ISGetSize(labelIS, &numSubVertices);CHKERRQ(ierr);
8984   ierr = ISGetIndices(labelIS, &subVertices);CHKERRQ(ierr);
8985   maxSubCells = numSubVertices;
8986   ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &subCells);CHKERRQ(ierr);
8987   ierr = PetscMalloc(numSubVertices * sizeof(PetscInt), &subVerticesActive);CHKERRQ(ierr);
8988   ierr = PetscMemzero(subVerticesActive, numSubVertices * sizeof(PetscInt));CHKERRQ(ierr);
8989   for(v = 0; v < numSubVertices; ++v) {
8990     const PetscInt vertex = subVertices[v];
8991     PetscInt *star = PETSC_NULL;
8992     PetscInt  starSize, numCells = 0;
8993 
8994     ierr = DMPlexGetTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
8995     for(p = 0; p < starSize*2; p += 2) {
8996       const PetscInt point = star[p];
8997       if ((point >= cStart) && (point < cEnd)) {
8998         star[numCells++] = point;
8999       }
9000     }
9001     numOldSubCells = numSubCells;
9002     for(c = 0; c < numCells; ++c) {
9003       const PetscInt cell    = star[c];
9004       PetscInt      *closure = PETSC_NULL;
9005       PetscInt       closureSize, numCorners = 0, faceSize = 0;
9006       PetscInt       cellLoc;
9007 
9008       ierr = PetscFindInt(cell, numOldSubCells, subCells, &cellLoc);CHKERRQ(ierr);
9009       if (cellLoc >= 0) continue;
9010       ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9011       for(p = 0; p < closureSize*2; p += 2) {
9012         const PetscInt point = closure[p];
9013         if ((point >= vStart) && (point < vEnd)) {
9014           closure[numCorners++] = point;
9015         }
9016       }
9017       if (!nFV) {ierr = DMPlexGetNumFaceVertices(dm, numCorners, &nFV);CHKERRQ(ierr);}
9018       for(corner = 0; corner < numCorners; ++corner) {
9019         const PetscInt cellVertex = closure[corner];
9020         PetscInt       subVertex;
9021 
9022         ierr = PetscFindInt(cellVertex, numSubVertices, subVertices, &subVertex);CHKERRQ(ierr);
9023         if (subVertex >= 0) { /* contains submesh vertex */
9024           for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9025           if (i == faceSize) {
9026             if (faceSize >= maxConeSize) SETERRQ2(comm, PETSC_ERR_ARG_OUTOFRANGE, "Number of vertices in face %d should not exceed %d", faceSize+1, maxConeSize);
9027             face[faceSize]    = cellVertex;
9028             subface[faceSize] = subVertex;
9029             ++faceSize;
9030           }
9031         }
9032       }
9033       ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9034       if (faceSize >= nFV) {
9035         if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9036         if (numSubCells >= maxSubCells) {
9037           PetscInt *tmpCells;
9038           maxSubCells *= 2;
9039           ierr = PetscMalloc(maxSubCells * sizeof(PetscInt), &tmpCells);CHKERRQ(ierr);
9040           ierr = PetscMemcpy(tmpCells, subCells, numSubCells * sizeof(PetscInt));CHKERRQ(ierr);
9041           ierr = PetscFree(subCells);CHKERRQ(ierr);
9042           subCells = tmpCells;
9043         }
9044         /* TOOD: Maybe overestimate then squeeze out empty faces */
9045         if (faceSize > nFV) {
9046           /* TODO: This is tricky. Maybe just add all faces */
9047           numSubFaces++;
9048         } else {
9049           numSubFaces++;
9050         }
9051         for(f = 0; f < faceSize; ++f) {
9052           subVerticesActive[subface[f]] = 1;
9053         }
9054         subCells[numSubCells++] = cell;
9055       }
9056     }
9057     ierr = DMPlexRestoreTransitiveClosure(dm, vertex, PETSC_FALSE, &starSize, &star);CHKERRQ(ierr);
9058     ierr = PetscSortRemoveDupsInt(&numSubCells, subCells);CHKERRQ(ierr);
9059   }
9060   /* Pick out active subvertices */
9061   for(v = 0, numSubVerticesActive = 0; v < numSubVertices; ++v) {
9062     if (subVerticesActive[v]) {
9063       subVerticesActive[numSubVerticesActive++] = subVertices[v];
9064     }
9065   }
9066   ierr = DMPlexSetChart(*subdm, 0, numSubCells+numSubFaces+numSubVerticesActive);CHKERRQ(ierr);
9067   /* Set cone sizes */
9068   firstSubVertex = numSubCells;
9069   firstSubFace   = numSubCells+numSubVerticesActive;
9070   newFacePoint   = firstSubFace;
9071   for(c = 0; c < numSubCells; ++c) {
9072     ierr = DMPlexSetConeSize(*subdm, c, 1);CHKERRQ(ierr);
9073   }
9074   for(f = firstSubFace; f < firstSubFace+numSubFaces; ++f) {
9075     ierr = DMPlexSetConeSize(*subdm, f, nFV);CHKERRQ(ierr);
9076   }
9077   ierr = DMSetUp(*subdm);CHKERRQ(ierr);
9078   /* Create face cones */
9079   for(c = 0; c < numSubCells; ++c) {
9080     const PetscInt cell    = subCells[c];
9081     PetscInt      *closure = PETSC_NULL;
9082     PetscInt       closureSize, numCorners = 0, faceSize = 0;
9083 
9084     ierr = DMPlexGetTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9085     for(p = 0; p < closureSize*2; p += 2) {
9086       const PetscInt point = closure[p];
9087       if ((point >= vStart) && (point < vEnd)) {
9088         closure[numCorners++] = point;
9089       }
9090     }
9091     for(corner = 0; corner < numCorners; ++corner) {
9092       const PetscInt cellVertex = closure[corner];
9093       PetscInt       subVertex;
9094 
9095       ierr = PetscFindInt(cellVertex, numSubVerticesActive, subVerticesActive, &subVertex);CHKERRQ(ierr);
9096       if (subVertex >= 0) { /* contains submesh vertex */
9097         for(i = 0; i < faceSize; ++i) {if (cellVertex == face[i]) break;}
9098         if (i == faceSize) {
9099           face[faceSize]    = cellVertex;
9100           subface[faceSize] = numSubCells+subVertex;
9101           ++faceSize;
9102         }
9103       }
9104     }
9105     ierr = DMPlexRestoreTransitiveClosure(dm, cell, PETSC_TRUE, &closureSize, &closure);CHKERRQ(ierr);
9106     if (faceSize >= nFV) {
9107       if (faceSize > nFV && !boundaryFaces) SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid submesh: Too many vertices %d of an element on the surface", faceSize);
9108       // Here we allow a set of vertices to lie completely on a boundary cell (like a corner tetrahedron)
9109       //   We have to take all the faces, and discard those in the interior
9110       //   We check the join of the face vertices, which produces 2 cells if in the interior
9111 #if 0
9112       // This object just calls insert on each face that comes from subsets()
9113       // In fact, we can just always acll subsets(), since when we pass a single face it is a single call
9114       FaceInserterV<FlexMesh::sieve_type> inserter(mesh, sieve, subSieve, f, *c_iter, numCorners, indices, &origVertices, &faceVertices, &submeshCells);
9115       PointArray                          faceVec(face->begin(), face->end());
9116 
9117       subsets(faceVec, nFV, inserter);
9118 #endif
9119       ierr = DMPlexInsertFace_Private(dm, *subdm, faceSize, face, subface, numCorners, cell, c, firstSubFace, &newFacePoint);CHKERRQ(ierr);
9120     }
9121   }
9122   ierr = DMPlexSymmetrize(*subdm);CHKERRQ(ierr);
9123   ierr = DMPlexStratify(*subdm);CHKERRQ(ierr);
9124   /* Build coordinates */
9125   ierr = DMPlexGetCoordinateSection(dm, &coordSection);CHKERRQ(ierr);
9126   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9127   ierr = DMPlexGetCoordinateSection(*subdm, &subCoordSection);CHKERRQ(ierr);
9128   ierr = PetscSectionSetChart(subCoordSection, firstSubVertex, firstSubVertex+numSubVerticesActive);CHKERRQ(ierr);
9129   for (v = firstSubVertex; v < firstSubVertex+numSubVerticesActive; ++v) {
9130     ierr = PetscSectionSetDof(subCoordSection, v, dim);CHKERRQ(ierr);
9131   }
9132   ierr = PetscSectionSetUp(subCoordSection);CHKERRQ(ierr);
9133   ierr = PetscSectionGetStorageSize(subCoordSection, &coordSize);CHKERRQ(ierr);
9134   ierr = VecCreate(((PetscObject) dm)->comm, &subCoordinates);CHKERRQ(ierr);
9135   ierr = VecSetSizes(subCoordinates, coordSize, PETSC_DETERMINE);CHKERRQ(ierr);
9136   ierr = VecSetFromOptions(subCoordinates);CHKERRQ(ierr);
9137   ierr = VecGetArray(coordinates,    &coords);CHKERRQ(ierr);
9138   ierr = VecGetArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9139   for(v = 0; v < numSubVerticesActive; ++v) {
9140     const PetscInt vertex    = subVerticesActive[v];
9141     const PetscInt subVertex = firstSubVertex+v;
9142     PetscInt dof, off, sdof, soff;
9143 
9144     ierr = PetscSectionGetDof(coordSection, vertex, &dof);CHKERRQ(ierr);
9145     ierr = PetscSectionGetOffset(coordSection, vertex, &off);CHKERRQ(ierr);
9146     ierr = PetscSectionGetDof(subCoordSection, subVertex, &sdof);CHKERRQ(ierr);
9147     ierr = PetscSectionGetOffset(subCoordSection, subVertex, &soff);CHKERRQ(ierr);
9148     if (dof != sdof) SETERRQ4(comm, PETSC_ERR_PLIB, "Coordinate dimension %d on subvertex %d, vertex %d should be %d", sdof, subVertex, vertex, dof);
9149     for(d = 0; d < dof; ++d) {
9150       subCoords[soff+d] = coords[off+d];
9151     }
9152   }
9153   ierr = VecRestoreArray(coordinates,    &coords);CHKERRQ(ierr);
9154   ierr = VecRestoreArray(subCoordinates, &subCoords);CHKERRQ(ierr);
9155   ierr = DMSetCoordinatesLocal(*subdm, subCoordinates);CHKERRQ(ierr);
9156   ierr = VecDestroy(&subCoordinates);CHKERRQ(ierr);
9157 
9158   ierr = DMPlexSetVTKCellHeight(*subdm, 1);CHKERRQ(ierr);
9159   /* Create map from submesh points to original mesh points */
9160   submesh = (DM_Plex *) (*subdm)->data;
9161   ierr = PetscMalloc((numSubCells+numSubVerticesActive) * sizeof(PetscInt), &tmpPoints);CHKERRQ(ierr);
9162   for(c = 0; c < numSubCells; ++c) {
9163     tmpPoints[c] = subCells[c];
9164   }
9165   for(v = numSubCells; v < numSubCells+numSubVerticesActive; ++v) {
9166     tmpPoints[v] = subVerticesActive[v-numSubCells];
9167   }
9168   ierr = ISCreateGeneral(comm, numSubCells+numSubVerticesActive, tmpPoints, PETSC_OWN_POINTER, &submesh->subpointMap);CHKERRQ(ierr);
9169 
9170   ierr = PetscFree(subCells);CHKERRQ(ierr);
9171   ierr = PetscFree(subVerticesActive);CHKERRQ(ierr);
9172   ierr = ISRestoreIndices(labelIS, &subVertices);CHKERRQ(ierr);
9173   ierr = ISDestroy(&labelIS);CHKERRQ(ierr);
9174   ierr = DMRestoreWorkArray(dm, 2*maxConeSize, PETSC_INT, &face);CHKERRQ(ierr);
9175   PetscFunctionReturn(0);
9176 }
9177 
9178 #undef __FUNCT__
9179 #define __FUNCT__ "DMPlexCreateNumbering_Private"
9180 /* We can easily have a form that takes an IS instead */
9181 PetscErrorCode DMPlexCreateNumbering_Private(DM dm, PetscInt pStart, PetscInt pEnd, PetscSF sf, IS *numbering)
9182 {
9183   PetscSection   section, globalSection;
9184   PetscInt      *numbers, p;
9185   PetscErrorCode ierr;
9186 
9187   PetscFunctionBegin;
9188   ierr = PetscSectionCreate(((PetscObject) dm)->comm, &section);CHKERRQ(ierr);
9189   ierr = PetscSectionSetChart(section, pStart, pEnd);CHKERRQ(ierr);
9190   for(p = pStart; p < pEnd; ++p) {
9191     ierr = PetscSectionSetDof(section, p, 1);CHKERRQ(ierr);
9192   }
9193   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
9194   ierr = PetscSectionCreateGlobalSection(section, sf, PETSC_FALSE, &globalSection);CHKERRQ(ierr);
9195   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &numbers);CHKERRQ(ierr);
9196   for(p = pStart; p < pEnd; ++p) {
9197     ierr = PetscSectionGetOffset(globalSection, p, &numbers[p-pStart]);CHKERRQ(ierr);
9198   }
9199   ierr = ISCreateGeneral(((PetscObject) dm)->comm, pEnd - pStart, numbers, PETSC_OWN_POINTER, numbering);CHKERRQ(ierr);
9200   ierr = PetscSectionDestroy(&section);CHKERRQ(ierr);
9201   ierr = PetscSectionDestroy(&globalSection);CHKERRQ(ierr);
9202   PetscFunctionReturn(0);
9203 }
9204 
9205 #undef __FUNCT__
9206 #define __FUNCT__ "DMPlexGetCellNumbering"
9207 PetscErrorCode DMPlexGetCellNumbering(DM dm, IS *globalCellNumbers)
9208 {
9209   DM_Plex    *mesh = (DM_Plex *) dm->data;
9210   PetscInt       cellHeight, cStart, cEnd, cMax;
9211   PetscErrorCode ierr;
9212 
9213   PetscFunctionBegin;
9214   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9215   if (!mesh->globalCellNumbers) {
9216     ierr = DMPlexGetVTKCellHeight(dm, &cellHeight);CHKERRQ(ierr);
9217     ierr = DMPlexGetHeightStratum(dm, cellHeight, &cStart, &cEnd);CHKERRQ(ierr);
9218     ierr = DMPlexGetVTKBounds(dm, &cMax, PETSC_NULL);CHKERRQ(ierr);
9219     if (cMax >= 0) {cEnd = PetscMin(cEnd, cMax);}
9220     ierr = DMPlexCreateNumbering_Private(dm, cStart, cEnd, dm->sf, &mesh->globalCellNumbers);CHKERRQ(ierr);
9221   }
9222   *globalCellNumbers = mesh->globalCellNumbers;
9223   PetscFunctionReturn(0);
9224 }
9225 
9226 #undef __FUNCT__
9227 #define __FUNCT__ "DMPlexGetVertexNumbering"
9228 PetscErrorCode DMPlexGetVertexNumbering(DM dm, IS *globalVertexNumbers)
9229 {
9230   DM_Plex    *mesh = (DM_Plex *) dm->data;
9231   PetscInt       vStart, vEnd, vMax;
9232   PetscErrorCode ierr;
9233 
9234   PetscFunctionBegin;
9235   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9236   if (!mesh->globalVertexNumbers) {
9237     ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9238     ierr = DMPlexGetVTKBounds(dm, PETSC_NULL, &vMax);CHKERRQ(ierr);
9239     if (vMax >= 0) {vEnd = PetscMin(vEnd, vMax);}
9240     ierr = DMPlexCreateNumbering_Private(dm, vStart, vEnd, dm->sf, &mesh->globalVertexNumbers);CHKERRQ(ierr);
9241   }
9242   *globalVertexNumbers = mesh->globalVertexNumbers;
9243   PetscFunctionReturn(0);
9244 }
9245 
9246 #undef __FUNCT__
9247 #define __FUNCT__ "DMPlexGetSubpointMap"
9248 PetscErrorCode DMPlexGetSubpointMap(DM dm, IS *subpointMap)
9249 {
9250   DM_Plex *mesh = (DM_Plex *) dm->data;
9251 
9252   PetscFunctionBegin;
9253   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9254   PetscValidPointer(subpointMap, 2);
9255   *subpointMap = mesh->subpointMap;
9256   PetscFunctionReturn(0);
9257 }
9258 
9259 #undef __FUNCT__
9260 #define __FUNCT__ "DMPlexSetSubpointMap"
9261 /* Note: Should normally not be called by the user, since it is set in DMPlexCreateSubmesh() */
9262 PetscErrorCode DMPlexSetSubpointMap(DM dm, IS subpointMap)
9263 {
9264   DM_Plex *mesh = (DM_Plex *) dm->data;
9265 
9266   PetscFunctionBegin;
9267   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9268   PetscValidHeaderSpecific(subpointMap, IS_CLASSID, 2);
9269   mesh->subpointMap = subpointMap;
9270   PetscFunctionReturn(0);
9271 }
9272 
9273 #undef __FUNCT__
9274 #define __FUNCT__ "DMPlexGetScale"
9275 PetscErrorCode DMPlexGetScale(DM dm, PetscUnit unit, PetscReal *scale)
9276 {
9277   DM_Plex *mesh = (DM_Plex *) dm->data;
9278 
9279   PetscFunctionBegin;
9280   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9281   PetscValidPointer(scale, 3);
9282   *scale = mesh->scale[unit];
9283   PetscFunctionReturn(0);
9284 }
9285 
9286 #undef __FUNCT__
9287 #define __FUNCT__ "DMPlexSetScale"
9288 PetscErrorCode DMPlexSetScale(DM dm, PetscUnit unit, PetscReal scale)
9289 {
9290   DM_Plex *mesh = (DM_Plex *) dm->data;
9291 
9292   PetscFunctionBegin;
9293   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9294   mesh->scale[unit] = scale;
9295   PetscFunctionReturn(0);
9296 }
9297 
9298 
9299 /*******************************************************************************
9300 This should be in a separate Discretization object, but I am not sure how to lay
9301 it out yet, so I am stuffing things here while I experiment.
9302 *******************************************************************************/
9303 #undef __FUNCT__
9304 #define __FUNCT__ "DMPlexSetFEMIntegration"
9305 PetscErrorCode DMPlexSetFEMIntegration(DM dm,
9306                                           PetscErrorCode (*integrateResidualFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9307                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9308                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9309                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9310                                           PetscErrorCode (*integrateJacobianActionFEM)(PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[], const PetscScalar[],
9311                                                                                        const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9312                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9313                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9314                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9315                                                                                        void (**)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]),
9316                                           PetscErrorCode (*integrateJacobianFEM)(PetscInt, PetscInt, PetscInt, PetscInt, PetscQuadrature[], const PetscScalar[],
9317                                                                                  const PetscReal[], const PetscReal[], const PetscReal[], const PetscReal[],
9318                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9319                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9320                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]),
9321                                                                                  void (*)(const PetscScalar[], const PetscScalar[], const PetscReal[], PetscScalar[]), PetscScalar[]))
9322 {
9323   DM_Plex *mesh = (DM_Plex *) dm->data;
9324 
9325   PetscFunctionBegin;
9326   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
9327   mesh->integrateResidualFEM       = integrateResidualFEM;
9328   mesh->integrateJacobianActionFEM = integrateJacobianActionFEM;
9329   mesh->integrateJacobianFEM       = integrateJacobianFEM;
9330   PetscFunctionReturn(0);
9331 }
9332 
9333 #undef __FUNCT__
9334 #define __FUNCT__ "DMPlexProjectFunctionLocal"
9335 PetscErrorCode DMPlexProjectFunctionLocal(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec localX)
9336 {
9337   Vec            coordinates;
9338   PetscSection   section, cSection;
9339   PetscInt       dim, vStart, vEnd, v, c, d;
9340   PetscScalar   *values, *cArray;
9341   PetscReal     *coords;
9342   PetscErrorCode ierr;
9343 
9344   PetscFunctionBegin;
9345   ierr = DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd);CHKERRQ(ierr);
9346   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9347   ierr = DMPlexGetCoordinateSection(dm, &cSection);CHKERRQ(ierr);
9348   ierr = DMGetCoordinatesLocal(dm, &coordinates);CHKERRQ(ierr);
9349   ierr = PetscMalloc(numComp * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9350   ierr = VecGetArray(coordinates, &cArray);CHKERRQ(ierr);
9351   ierr = PetscSectionGetDof(cSection, vStart, &dim);CHKERRQ(ierr);
9352   ierr = PetscMalloc(dim * sizeof(PetscReal),&coords);CHKERRQ(ierr);
9353   for (v = vStart; v < vEnd; ++v) {
9354     PetscInt dof, off;
9355 
9356     ierr = PetscSectionGetDof(cSection, v, &dof);CHKERRQ(ierr);
9357     ierr = PetscSectionGetOffset(cSection, v, &off);CHKERRQ(ierr);
9358     if (dof > dim) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_WRONG, "Cannot have more coordinates %d then dimensions %d", dof, dim);
9359     for(d = 0; d < dof; ++d) {
9360       coords[d] = PetscRealPart(cArray[off+d]);
9361     }
9362     for(c = 0; c < numComp; ++c) {
9363       values[c] = (*funcs[c])(coords);
9364     }
9365     ierr = VecSetValuesSection(localX, section, v, values, mode);CHKERRQ(ierr);
9366   }
9367   ierr = VecRestoreArray(coordinates, &cArray);CHKERRQ(ierr);
9368   /* Temporary, must be replaced by a projection on the finite element basis */
9369   {
9370     PetscInt eStart = 0, eEnd = 0, e, depth;
9371 
9372     ierr = DMPlexGetLabelSize(dm, "depth", &depth);CHKERRQ(ierr);
9373     --depth;
9374     if (depth > 1) {ierr = DMPlexGetDepthStratum(dm, 1, &eStart, &eEnd);CHKERRQ(ierr);}
9375     for (e = eStart; e < eEnd; ++e) {
9376       const PetscInt *cone = PETSC_NULL;
9377       PetscInt        coneSize, d;
9378       PetscScalar    *coordsA, *coordsB;
9379 
9380       ierr = DMPlexGetConeSize(dm, e, &coneSize);CHKERRQ(ierr);
9381       ierr = DMPlexGetCone(dm, e, &cone);CHKERRQ(ierr);
9382       if (coneSize != 2) SETERRQ2(((PetscObject) dm)->comm, PETSC_ERR_ARG_SIZ, "Cone size %d for point %d should be 2", coneSize, e);
9383       ierr = VecGetValuesSection(coordinates, cSection, cone[0], &coordsA);CHKERRQ(ierr);
9384       ierr = VecGetValuesSection(coordinates, cSection, cone[1], &coordsB);CHKERRQ(ierr);
9385       for (d = 0; d < dim; ++d) {
9386         coords[d] = 0.5*(PetscRealPart(coordsA[d]) + PetscRealPart(coordsB[d]));
9387       }
9388       for (c = 0; c < numComp; ++c) {
9389         values[c] = (*funcs[c])(coords);
9390       }
9391       ierr = VecSetValuesSection(localX, section, e, values, mode);CHKERRQ(ierr);
9392     }
9393   }
9394 
9395   ierr = PetscFree(coords);CHKERRQ(ierr);
9396   ierr = PetscFree(values);CHKERRQ(ierr);
9397 #if 0
9398   const PetscInt localDof = this->_mesh->sizeWithBC(s, *cells->begin());
9399   PetscReal      detJ;
9400 
9401   ierr = PetscMalloc(localDof * sizeof(PetscScalar), &values);CHKERRQ(ierr);
9402   ierr = PetscMalloc2(dim,PetscReal,&v0,dim*dim,PetscReal,&J);CHKERRQ(ierr);
9403   ALE::ISieveVisitor::PointRetriever<PETSC_MESH_TYPE::sieve_type> pV((int) pow(this->_mesh->getSieve()->getMaxConeSize(), dim+1)+1, true);
9404 
9405   for (PetscInt c = cStart; c < cEnd; ++c) {
9406     ALE::ISieveTraversal<PETSC_MESH_TYPE::sieve_type>::orientedClosure(*this->_mesh->getSieve(), c, pV);
9407     const PETSC_MESH_TYPE::point_type *oPoints = pV.getPoints();
9408     const int                          oSize   = pV.getSize();
9409     int                                v       = 0;
9410 
9411     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, PETSC_NULL, &detJ);CHKERRQ(ierr);
9412     for (PetscInt cl = 0; cl < oSize; ++cl) {
9413       const PetscInt fDim;
9414 
9415       ierr = PetscSectionGetDof(oPoints[cl], &fDim);CHKERRQ(ierr);
9416       if (pointDim) {
9417         for (PetscInt d = 0; d < fDim; ++d, ++v) {
9418           values[v] = (*this->_options.integrate)(v0, J, v, initFunc);
9419         }
9420       }
9421     }
9422     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, localX, c, values);CHKERRQ(ierr);
9423     pV.clear();
9424   }
9425   ierr = PetscFree2(v0,J);CHKERRQ(ierr);
9426   ierr = PetscFree(values);CHKERRQ(ierr);
9427 #endif
9428   PetscFunctionReturn(0);
9429 }
9430 
9431 #undef __FUNCT__
9432 #define __FUNCT__ "DMPlexProjectFunction"
9433 /*@C
9434   DMPlexProjectFunction - This projects the given function into the function space provided.
9435 
9436   Input Parameters:
9437 + dm      - The DM
9438 . numComp - The number of components (functions)
9439 . funcs   - The coordinate functions to evaluate
9440 - mode    - The insertion mode for values
9441 
9442   Output Parameter:
9443 . X - vector
9444 
9445   Level: developer
9446 
9447   Note:
9448   This currently just calls the function with the coordinates of each vertex and edge midpoint, and stores the result in a vector.
9449   We will eventually fix it.
9450 
9451 ,seealso: DMPlexComputeL2Diff()
9452 */
9453 PetscErrorCode DMPlexProjectFunction(DM dm, PetscInt numComp, PetscScalar (**funcs)(const PetscReal []), InsertMode mode, Vec X)
9454 {
9455   Vec            localX;
9456   PetscErrorCode ierr;
9457 
9458   PetscFunctionBegin;
9459   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9460   ierr = DMPlexProjectFunctionLocal(dm, numComp, funcs, mode, localX);CHKERRQ(ierr);
9461   ierr = DMLocalToGlobalBegin(dm, localX, mode, X);CHKERRQ(ierr);
9462   ierr = DMLocalToGlobalEnd(dm, localX, mode, X);CHKERRQ(ierr);
9463   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9464   PetscFunctionReturn(0);
9465 }
9466 
9467 #undef __FUNCT__
9468 #define __FUNCT__ "DMPlexComputeL2Diff"
9469 /*@C
9470   DMPlexComputeL2Diff - This function computes the L_2 difference between a function u and an FEM interpolant solution u_h.
9471 
9472   Input Parameters:
9473 + dm    - The DM
9474 . quad  - The PetscQuadrature object for each field
9475 . funcs - The functions to evaluate for each field component
9476 - X     - The coefficient vector u_h
9477 
9478   Output Parameter:
9479 . diff - The diff ||u - u_h||_2
9480 
9481   Level: developer
9482 
9483 .seealso: DMPlexProjectFunction()
9484 */
9485 PetscErrorCode DMPlexComputeL2Diff(DM dm, PetscQuadrature quad[], PetscScalar (**funcs)(const PetscReal []), Vec X, PetscReal *diff) {
9486   const PetscInt   debug = 0;
9487   PetscSection     section;
9488   Vec              localX;
9489   PetscReal       *coords, *v0, *J, *invJ, detJ;
9490   PetscReal        localDiff = 0.0;
9491   PetscInt         dim, numFields, numComponents = 0, cStart, cEnd, c, field, fieldOffset, comp;
9492   PetscErrorCode   ierr;
9493 
9494   PetscFunctionBegin;
9495   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9496   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9497   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9498   ierr = DMGetLocalVector(dm, &localX);CHKERRQ(ierr);
9499   ierr = DMGlobalToLocalBegin(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9500   ierr = DMGlobalToLocalEnd(dm, X, INSERT_VALUES, localX);CHKERRQ(ierr);
9501   for (field = 0; field < numFields; ++field) {
9502     numComponents += quad[field].numComponents;
9503   }
9504   ierr = DMPlexProjectFunctionLocal(dm, numComponents, funcs, INSERT_BC_VALUES, localX);CHKERRQ(ierr);
9505   ierr = PetscMalloc4(dim,PetscReal,&coords,dim,PetscReal,&v0,dim*dim,PetscReal,&J,dim*dim,PetscReal,&invJ);CHKERRQ(ierr);
9506   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9507   for (c = cStart; c < cEnd; ++c) {
9508     const PetscScalar *x;
9509     PetscReal          elemDiff = 0.0;
9510 
9511     ierr = DMPlexComputeCellGeometry(dm, c, v0, J, invJ, &detJ);CHKERRQ(ierr);
9512     if (detJ <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ, c);
9513     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
9514 
9515     for (field = 0, comp = 0, fieldOffset = 0; field < numFields; ++field) {
9516       const PetscInt   numQuadPoints = quad[field].numQuadPoints;
9517       const PetscReal *quadPoints    = quad[field].quadPoints;
9518       const PetscReal *quadWeights   = quad[field].quadWeights;
9519       const PetscInt   numBasisFuncs = quad[field].numBasisFuncs;
9520       const PetscInt   numBasisComps = quad[field].numComponents;
9521       const PetscReal *basis         = quad[field].basis;
9522       PetscInt         q, d, e, fc, f;
9523 
9524       if (debug) {
9525         char title[1024];
9526         ierr = PetscSNPrintf(title, 1023, "Solution for Field %d", field);CHKERRQ(ierr);
9527         ierr = DMPrintCellVector(c, title, numBasisFuncs*numBasisComps, &x[fieldOffset]);CHKERRQ(ierr);
9528       }
9529       for (q = 0; q < numQuadPoints; ++q) {
9530         for (d = 0; d < dim; d++) {
9531           coords[d] = v0[d];
9532           for (e = 0; e < dim; e++) {
9533             coords[d] += J[d*dim+e]*(quadPoints[q*dim+e] + 1.0);
9534           }
9535         }
9536         for (fc = 0; fc < numBasisComps; ++fc) {
9537           const PetscReal funcVal     = PetscRealPart((*funcs[comp+fc])(coords));
9538           PetscReal       interpolant = 0.0;
9539           for (f = 0; f < numBasisFuncs; ++f) {
9540             const PetscInt fidx = f*numBasisComps+fc;
9541             interpolant += PetscRealPart(x[fieldOffset+fidx])*basis[q*numBasisFuncs*numBasisComps+fidx];
9542           }
9543           if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "    elem %d field %d diff %g\n", c, field, PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ);CHKERRQ(ierr);}
9544           elemDiff += PetscSqr(interpolant - funcVal)*quadWeights[q]*detJ;
9545         }
9546       }
9547       comp        += numBasisComps;
9548       fieldOffset += numBasisFuncs*numBasisComps;
9549     }
9550     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, localX, c, PETSC_NULL, &x);CHKERRQ(ierr);
9551     if (debug) {ierr = PetscPrintf(PETSC_COMM_SELF, "  elem %d diff %g\n", c, elemDiff);CHKERRQ(ierr);}
9552     localDiff += elemDiff;
9553   }
9554   ierr = PetscFree4(coords,v0,J,invJ);CHKERRQ(ierr);
9555   ierr = DMRestoreLocalVector(dm, &localX);CHKERRQ(ierr);
9556   ierr = MPI_Allreduce(&localDiff, diff, 1, MPIU_REAL, MPI_SUM, PETSC_COMM_WORLD);CHKERRQ(ierr);
9557   *diff = PetscSqrtReal(*diff);
9558   PetscFunctionReturn(0);
9559 }
9560 
9561 #undef __FUNCT__
9562 #define __FUNCT__ "DMPlexComputeResidualFEM"
9563 /*@
9564   DMPlexComputeResidualFEM - Form the local residual F from the local input X using pointwise functions specified by the user
9565 
9566   Input Parameters:
9567 + dm - The mesh
9568 . X  - Local input vector
9569 - user - The user context
9570 
9571   Output Parameter:
9572 . F  - Local output vector
9573 
9574   Note:
9575   The second member of the user context must be an FEMContext.
9576 
9577   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9578   like a GPU, or vectorize on a multicore machine.
9579 
9580 .seealso: DMPlexComputeJacobianActionFEM()
9581 */
9582 PetscErrorCode DMPlexComputeResidualFEM(DM dm, Vec X, Vec F, void *user)
9583 {
9584   DM_Plex      *mesh = (DM_Plex *) dm->data;
9585   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9586   PetscQuadrature *quad = fem->quad;
9587   PetscSection     section;
9588   PetscReal       *v0, *J, *invJ, *detJ;
9589   PetscScalar     *elemVec, *u;
9590   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9591   PetscInt         cellDof = 0, numComponents = 0;
9592   PetscErrorCode   ierr;
9593 
9594   PetscFunctionBegin;
9595   /* ierr = PetscLogEventBegin(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9596   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9597   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9598   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9599   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9600   numCells = cEnd - cStart;
9601   for (field = 0; field < numFields; ++field) {
9602     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9603     numComponents += quad[field].numComponents;
9604   }
9605   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9606   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9607   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);
9608   for (c = cStart; c < cEnd; ++c) {
9609     const PetscScalar *x;
9610     PetscInt           i;
9611 
9612     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9613     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9614     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9615 
9616     for (i = 0; i < cellDof; ++i) {
9617       u[c*cellDof+i] = x[i];
9618     }
9619     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9620   }
9621   for (field = 0; field < numFields; ++field) {
9622     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9623     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9624     void (*f0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f0[]) = fem->f0Funcs[field];
9625     void (*f1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar f1[]) = fem->f1Funcs[field];
9626     /* Conforming batches */
9627     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9628     PetscInt numBlocks  = 1;
9629     PetscInt batchSize  = numBlocks * blockSize;
9630     PetscInt numBatches = numBatchesTmp;
9631     PetscInt numChunks  = numCells / (numBatches*batchSize);
9632     /* Remainder */
9633     PetscInt numRemainder = numCells % (numBatches * batchSize);
9634     PetscInt offset       = numCells - numRemainder;
9635 
9636     ierr = (*mesh->integrateResidualFEM)(numChunks*numBatches*batchSize, numFields, field, quad, u, v0, J, invJ, detJ, f0, f1, elemVec);CHKERRQ(ierr);
9637     ierr = (*mesh->integrateResidualFEM)(numRemainder, numFields, field, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9638                                          f0, f1, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9639   }
9640   for (c = cStart; c < cEnd; ++c) {
9641     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Residual", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9642     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9643   }
9644   ierr = PetscFree6(u,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9645   if (mesh->printFEM) {
9646     PetscMPIInt rank, numProcs;
9647     PetscInt    p;
9648 
9649     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9650     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9651     ierr = PetscPrintf(PETSC_COMM_WORLD, "Residual:\n");CHKERRQ(ierr);
9652     for (p = 0; p < numProcs; ++p) {
9653       if (p == rank) {
9654         Vec f;
9655 
9656         ierr = VecDuplicate(F, &f);CHKERRQ(ierr);
9657         ierr = VecCopy(F, f);CHKERRQ(ierr);
9658         ierr = VecChop(f, 1.0e-10);CHKERRQ(ierr);
9659         ierr = VecView(f, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9660         ierr = VecDestroy(&f);CHKERRQ(ierr);
9661         ierr = PetscViewerFlush(PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);
9662       }
9663       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9664     }
9665   }
9666   /* ierr = PetscLogEventEnd(ResidualFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9667   PetscFunctionReturn(0);
9668 }
9669 
9670 #undef __FUNCT__
9671 #define __FUNCT__ "DMPlexComputeJacobianActionFEM"
9672 /*@C
9673   DMPlexComputeJacobianActionFEM - Form the local action of Jacobian J(u) on the local input X using pointwise functions specified by the user
9674 
9675   Input Parameters:
9676 + dm - The mesh
9677 . J  - The Jacobian shell matrix
9678 . X  - Local input vector
9679 - user - The user context
9680 
9681   Output Parameter:
9682 . F  - Local output vector
9683 
9684   Note:
9685   The second member of the user context must be an FEMContext.
9686 
9687   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9688   like a GPU, or vectorize on a multicore machine.
9689 
9690 .seealso: DMPlexComputeResidualFEM()
9691 */
9692 PetscErrorCode DMPlexComputeJacobianActionFEM(DM dm, Mat Jac, Vec X, Vec F, void *user)
9693 {
9694   DM_Plex      *mesh = (DM_Plex *) dm->data;
9695   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9696   PetscQuadrature *quad = fem->quad;
9697   PetscSection     section;
9698   JacActionCtx    *jctx;
9699   PetscReal       *v0, *J, *invJ, *detJ;
9700   PetscScalar     *elemVec, *u, *a;
9701   PetscInt         dim, numFields, field, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9702   PetscInt         cellDof = 0;
9703   PetscErrorCode   ierr;
9704 
9705   PetscFunctionBegin;
9706   /* ierr = PetscLogEventBegin(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9707   ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9708   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9709   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9710   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9711   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9712   numCells = cEnd - cStart;
9713   for (field = 0; field < numFields; ++field) {
9714     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9715   }
9716   ierr = VecSet(F, 0.0);CHKERRQ(ierr);
9717   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);
9718   for (c = cStart; c < cEnd; ++c) {
9719     const PetscScalar *x;
9720     PetscInt           i;
9721 
9722     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9723     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9724     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
9725     for (i = 0; i < cellDof; ++i) {
9726       u[c*cellDof+i] = x[i];
9727     }
9728     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, jctx->u, c, PETSC_NULL, &x);CHKERRQ(ierr);
9729     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9730     for (i = 0; i < cellDof; ++i) {
9731       a[c*cellDof+i] = x[i];
9732     }
9733     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9734   }
9735   for (field = 0; field < numFields; ++field) {
9736     const PetscInt numQuadPoints = quad[field].numQuadPoints;
9737     const PetscInt numBasisFuncs = quad[field].numBasisFuncs;
9738     /* Conforming batches */
9739     PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9740     PetscInt numBlocks  = 1;
9741     PetscInt batchSize  = numBlocks * blockSize;
9742     PetscInt numBatches = numBatchesTmp;
9743     PetscInt numChunks  = numCells / (numBatches*batchSize);
9744     /* Remainder */
9745     PetscInt numRemainder = numCells % (numBatches * batchSize);
9746     PetscInt offset       = numCells - numRemainder;
9747 
9748     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);
9749     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],
9750                                                fem->g0Funcs, fem->g1Funcs, fem->g2Funcs, fem->g3Funcs, &elemVec[offset*cellDof]);CHKERRQ(ierr);
9751   }
9752   for (c = cStart; c < cEnd; ++c) {
9753     if (mesh->printFEM > 1) {ierr = DMPrintCellVector(c, "Jacobian Action", cellDof, &elemVec[c*cellDof]);CHKERRQ(ierr);}
9754     ierr = DMPlexVecSetClosure(dm, PETSC_NULL, F, c, &elemVec[c*cellDof], ADD_VALUES);CHKERRQ(ierr);
9755   }
9756   ierr = PetscFree7(u,a,v0,J,invJ,detJ,elemVec);CHKERRQ(ierr);
9757   if (mesh->printFEM) {
9758     PetscMPIInt rank, numProcs;
9759     PetscInt    p;
9760 
9761     ierr = MPI_Comm_rank(((PetscObject) dm)->comm, &rank);CHKERRQ(ierr);
9762     ierr = MPI_Comm_size(((PetscObject) dm)->comm, &numProcs);CHKERRQ(ierr);
9763     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian Action:\n");CHKERRQ(ierr);
9764     for (p = 0; p < numProcs; ++p) {
9765       if (p == rank) {ierr = VecView(F, PETSC_VIEWER_STDOUT_SELF);CHKERRQ(ierr);}
9766       ierr = PetscBarrier((PetscObject) dm);CHKERRQ(ierr);
9767     }
9768   }
9769   /* ierr = PetscLogEventEnd(JacobianActionFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9770   PetscFunctionReturn(0);
9771 }
9772 
9773 #undef __FUNCT__
9774 #define __FUNCT__ "DMPlexComputeJacobianFEM"
9775 /*@
9776   DMPlexComputeJacobianFEM - Form the local portion of the Jacobian matrix J at the local solution X using pointwise functions specified by the user.
9777 
9778   Input Parameters:
9779 + dm - The mesh
9780 . X  - Local input vector
9781 - user - The user context
9782 
9783   Output Parameter:
9784 . Jac  - Jacobian matrix
9785 
9786   Note:
9787   The second member of the user context must be an FEMContext.
9788 
9789   We form the residual one batch of elements at a time. This allows us to offload work onto an accelerator,
9790   like a GPU, or vectorize on a multicore machine.
9791 
9792 .seealso: FormFunctionLocal()
9793 */
9794 PetscErrorCode DMPlexComputeJacobianFEM(DM dm, Vec X, Mat Jac, Mat JacP, MatStructure *str,void *user)
9795 {
9796   DM_Plex      *mesh = (DM_Plex *) dm->data;
9797   PetscFEM        *fem  = (PetscFEM *) &((DM *) user)[1];
9798   PetscQuadrature *quad = fem->quad;
9799   PetscSection     section;
9800   PetscReal       *v0, *J, *invJ, *detJ;
9801   PetscScalar     *elemMat, *u;
9802   PetscInt         dim, numFields, field, fieldI, numBatchesTmp = 1, numCells, cStart, cEnd, c;
9803   PetscInt         cellDof = 0, numComponents = 0;
9804   PetscBool        isShell;
9805   PetscErrorCode   ierr;
9806 
9807   PetscFunctionBegin;
9808   /* ierr = PetscLogEventBegin(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9809   ierr = DMPlexGetDimension(dm, &dim);CHKERRQ(ierr);
9810   ierr = DMGetDefaultSection(dm, &section);CHKERRQ(ierr);
9811   ierr = PetscSectionGetNumFields(section, &numFields);CHKERRQ(ierr);
9812   ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr);
9813   numCells = cEnd - cStart;
9814   for (field = 0; field < numFields; ++field) {
9815     cellDof += quad[field].numBasisFuncs*quad[field].numComponents;
9816     numComponents += quad[field].numComponents;
9817   }
9818   ierr = DMPlexProjectFunctionLocal(dm, numComponents, fem->bcFuncs, INSERT_BC_VALUES, X);CHKERRQ(ierr);
9819   ierr = MatZeroEntries(JacP);CHKERRQ(ierr);
9820   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);
9821   for (c = cStart; c < cEnd; ++c) {
9822     const PetscScalar *x;
9823     PetscInt           i;
9824 
9825     ierr = DMPlexComputeCellGeometry(dm, c, &v0[c*dim], &J[c*dim*dim], &invJ[c*dim*dim], &detJ[c]);CHKERRQ(ierr);
9826     if (detJ[c] <= 0.0) SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Invalid determinant %g for element %d", detJ[c], c);
9827     ierr = DMPlexVecGetClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9828 
9829     for (i = 0; i < cellDof; ++i) {
9830       u[c*cellDof+i] = x[i];
9831     }
9832     ierr = DMPlexVecRestoreClosure(dm, PETSC_NULL, X, c, PETSC_NULL, &x);CHKERRQ(ierr);
9833   }
9834   ierr = PetscMemzero(elemMat, numCells*cellDof*cellDof * sizeof(PetscScalar));CHKERRQ(ierr);
9835   for (fieldI = 0; fieldI < numFields; ++fieldI) {
9836     const PetscInt numQuadPoints = quad[fieldI].numQuadPoints;
9837     const PetscInt numBasisFuncs = quad[fieldI].numBasisFuncs;
9838     PetscInt       fieldJ;
9839 
9840     for (fieldJ = 0; fieldJ < numFields; ++fieldJ) {
9841       void (*g0)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g0[]) = fem->g0Funcs[fieldI*numFields+fieldJ];
9842       void (*g1)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g1[]) = fem->g1Funcs[fieldI*numFields+fieldJ];
9843       void (*g2)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g2[]) = fem->g2Funcs[fieldI*numFields+fieldJ];
9844       void (*g3)(const PetscScalar u[], const PetscScalar gradU[], const PetscReal x[], PetscScalar g3[]) = fem->g3Funcs[fieldI*numFields+fieldJ];
9845       /* Conforming batches */
9846       PetscInt blockSize  = numBasisFuncs*numQuadPoints;
9847       PetscInt numBlocks  = 1;
9848       PetscInt batchSize  = numBlocks * blockSize;
9849       PetscInt numBatches = numBatchesTmp;
9850       PetscInt numChunks  = numCells / (numBatches*batchSize);
9851       /* Remainder */
9852       PetscInt numRemainder = numCells % (numBatches * batchSize);
9853       PetscInt offset       = numCells - numRemainder;
9854 
9855       ierr = (*mesh->integrateJacobianFEM)(numChunks*numBatches*batchSize, numFields, fieldI, fieldJ, quad, u, v0, J, invJ, detJ, g0, g1, g2, g3, elemMat);CHKERRQ(ierr);
9856       ierr = (*mesh->integrateJacobianFEM)(numRemainder, numFields, fieldI, fieldJ, quad, &u[offset*cellDof], &v0[offset*dim], &J[offset*dim*dim], &invJ[offset*dim*dim], &detJ[offset],
9857                                            g0, g1, g2, g3, &elemMat[offset*cellDof*cellDof]);CHKERRQ(ierr);
9858     }
9859   }
9860   for (c = cStart; c < cEnd; ++c) {
9861     if (mesh->printFEM > 1) {ierr = DMPrintCellMatrix(c, "Jacobian", cellDof, cellDof, &elemMat[c*cellDof*cellDof]);CHKERRQ(ierr);}
9862     ierr = DMPlexMatSetClosure(dm, PETSC_NULL, PETSC_NULL, JacP, c, &elemMat[c*cellDof*cellDof], ADD_VALUES);CHKERRQ(ierr);
9863   }
9864   ierr = PetscFree6(u,v0,J,invJ,detJ,elemMat);CHKERRQ(ierr);
9865 
9866   /* Assemble matrix, using the 2-step process:
9867        MatAssemblyBegin(), MatAssemblyEnd(). */
9868   ierr = MatAssemblyBegin(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9869   ierr = MatAssemblyEnd(JacP, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
9870 
9871   if (mesh->printFEM) {
9872     ierr = PetscPrintf(PETSC_COMM_WORLD, "Jacobian:\n");CHKERRQ(ierr);
9873     ierr = MatChop(JacP, 1.0e-10);CHKERRQ(ierr);
9874     ierr = MatView(JacP, PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
9875   }
9876   /* ierr = PetscLogEventEnd(JacobianFEMEvent,0,0,0,0);CHKERRQ(ierr); */
9877   ierr = PetscObjectTypeCompare((PetscObject)Jac, MATSHELL, &isShell);CHKERRQ(ierr);
9878   if (isShell) {
9879     JacActionCtx *jctx;
9880 
9881     ierr = MatShellGetContext(Jac, &jctx);CHKERRQ(ierr);
9882     ierr = VecCopy(X, jctx->u);CHKERRQ(ierr);
9883   }
9884   *str = SAME_NONZERO_PATTERN;
9885   PetscFunctionReturn(0);
9886 }
9887 
9888 
9889 #undef __FUNCT__
9890 #define __FUNCT__ "PetscSectionCreateGlobalSectionLabel"
9891 /*@C
9892   PetscSectionCreateGlobalSectionLabel - Create a section describing the global field layout using
9893   the local section and an SF describing the section point overlap.
9894 
9895   Input Parameters:
9896   + s - The PetscSection for the local field layout
9897   . sf - The SF describing parallel layout of the section points
9898   . includeConstraints - By default this is PETSC_FALSE, meaning that the global field vector will not possess constrained dofs
9899   . label - The label specifying the points
9900   - labelValue - The label stratum specifying the points
9901 
9902   Output Parameter:
9903   . gsection - The PetscSection for the global field layout
9904 
9905   Note: This gives negative sizes and offsets to points not owned by this process
9906 
9907   Level: developer
9908 
9909 .seealso: PetscSectionCreate()
9910 @*/
9911 PetscErrorCode PetscSectionCreateGlobalSectionLabel(PetscSection s, PetscSF sf, PetscBool includeConstraints, DMLabel label, PetscInt labelValue, PetscSection *gsection)
9912 {
9913   PetscInt      *neg;
9914   PetscInt       pStart, pEnd, p, dof, cdof, off, globalOff = 0, nroots;
9915   PetscErrorCode ierr;
9916 
9917   PetscFunctionBegin;
9918   ierr = PetscSectionCreate(s->atlasLayout.comm, gsection);CHKERRQ(ierr);
9919   ierr = PetscSectionGetChart(s, &pStart, &pEnd);CHKERRQ(ierr);
9920   ierr = PetscSectionSetChart(*gsection, pStart, pEnd);CHKERRQ(ierr);
9921   ierr = PetscMalloc((pEnd - pStart) * sizeof(PetscInt), &neg);CHKERRQ(ierr);
9922   /* Mark ghost points with negative dof */
9923   for (p = pStart; p < pEnd; ++p) {
9924     PetscInt value;
9925 
9926     ierr = DMLabelGetValue(label, p, &value);CHKERRQ(ierr);
9927     if (value != labelValue) continue;
9928     ierr = PetscSectionGetDof(s, p, &dof);CHKERRQ(ierr);
9929     ierr = PetscSectionSetDof(*gsection, p, dof);CHKERRQ(ierr);
9930     ierr = PetscSectionGetConstraintDof(s, p, &cdof);CHKERRQ(ierr);
9931     if (!includeConstraints && cdof > 0) {ierr = PetscSectionSetConstraintDof(*gsection, p, cdof);CHKERRQ(ierr);}
9932     neg[p-pStart] = -(dof+1);
9933   }
9934   ierr = PetscSectionSetUpBC(*gsection);CHKERRQ(ierr);
9935   ierr = PetscSFGetGraph(sf, &nroots, PETSC_NULL, PETSC_NULL, PETSC_NULL);CHKERRQ(ierr);
9936   if (nroots >= 0) {
9937     if (nroots > pEnd - pStart) {
9938       PetscInt *tmpDof;
9939       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9940       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpDof);CHKERRQ(ierr);
9941       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9942       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpDof);CHKERRQ(ierr);
9943       for (p = pStart; p < pEnd; ++p) {
9944         if (tmpDof[p] < 0) {(*gsection)->atlasDof[p-pStart] = tmpDof[p];}
9945       }
9946       ierr = PetscFree(tmpDof);CHKERRQ(ierr);
9947     } else {
9948       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9949       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasDof[-pStart]);CHKERRQ(ierr);
9950     }
9951   }
9952   /* Calculate new sizes, get proccess offset, and calculate point offsets */
9953   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9954     cdof = (!includeConstraints && s->bc) ? s->bc->atlasDof[p] : 0;
9955     (*gsection)->atlasOff[p] = off;
9956     off += (*gsection)->atlasDof[p] > 0 ? (*gsection)->atlasDof[p]-cdof : 0;
9957   }
9958   ierr = MPI_Scan(&off, &globalOff, 1, MPIU_INT, MPI_SUM, s->atlasLayout.comm);CHKERRQ(ierr);
9959   globalOff -= off;
9960   for (p = 0, off = 0; p < pEnd-pStart; ++p) {
9961     (*gsection)->atlasOff[p] += globalOff;
9962     neg[p] = -((*gsection)->atlasOff[p]+1);
9963   }
9964   /* Put in negative offsets for ghost points */
9965   if (nroots >= 0) {
9966     if (nroots > pEnd - pStart) {
9967       PetscInt *tmpOff;
9968       /* Help Jed: HAVE TO MAKE A BUFFER HERE THE SIZE OF THE COMPLETE SPACE AND THEN COPY INTO THE atlasDof FOR THIS SECTION */
9969       ierr = PetscMalloc(nroots * sizeof(PetscInt), &tmpOff);CHKERRQ(ierr);
9970       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9971       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], tmpOff);CHKERRQ(ierr);
9972       for (p = pStart; p < pEnd; ++p) {
9973         if (tmpOff[p] < 0) {(*gsection)->atlasOff[p-pStart] = tmpOff[p];}
9974       }
9975       ierr = PetscFree(tmpOff);CHKERRQ(ierr);
9976     } else {
9977       ierr = PetscSFBcastBegin(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9978       ierr = PetscSFBcastEnd(sf, MPIU_INT, &neg[-pStart], &(*gsection)->atlasOff[-pStart]);CHKERRQ(ierr);
9979     }
9980   }
9981   ierr = PetscFree(neg);CHKERRQ(ierr);
9982   PetscFunctionReturn(0);
9983 }
9984